C# ListBox数据模板中的属性绑定不正确
我在让列表框正确绑定到集合时遇到了一些问题C# ListBox数据模板中的属性绑定不正确,c#,wpf,data-binding,mvvm,mvvm-light,C#,Wpf,Data Binding,Mvvm,Mvvm Light,我在让列表框正确绑定到集合时遇到了一些问题 public Foo() { Bars = new ObservableCollection<string>(); ... } 我将给出框架代码,然后解释我希望它做什么 XAML标记: <ListBox DataContext="{Binding Foos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Items
public Foo()
{
Bars = new ObservableCollection<string>();
...
}
我将给出框架代码,然后解释我希望它做什么
XAML标记:
<ListBox DataContext="{Binding Foos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding Main.SelectedFoo, Mode=TwoWay,
Source={StaticResource Locator},
UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding Main.SelectedFoo, Source={StaticResource Locator}}"/>
<ListBox ItemsSource="{Binding Main.SelectedFoo.Bars}" SelectedItem="{Binding Main.SelectedBar}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Right">
<!-- The binding requires "{Binding .}" because a path must be explicitly set for Two-Way binding,
even though {Binding .} is supposed to be identical to {Binding} -->
<TextBox Text="{Binding Path=. , UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
private ObservableCollection<Foo> _barList = new ObservableCollection<Foo>();
private const string BardListPN = "FooList";
public ObservableCollection<Foo> FooList
{
get { return _fooList; }
set
{
if (_fooList == value)
{
return;
}
var oldValue = _fooList;
_fooList = value;
RaisePropertyChanged(FooListPN);
}
}
private Foo _selectedFoo;
private const string SelectedFooPN = "SelectedFoo";
public Foo SelectedFoo
{
get { return _selectedFoo; }
set
{
if (_selectedFoo == value)
{
return;
}
var oldValue = _selectedFoo;
_selectedFoo = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedFooPN);
}
}
public const string SelectedBarPN = "SelectedBar";
private string _selectedBar = "";
public string SelectedBar
{
get
{
return _selectedBar;
}
set
{
if (_selectedBar == value)
{
return;
}
var oldValue = _selectedBar;
_selectedBar = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedBarPN);
}
}
public class Foo
{
public ICollection<string> Bars
{
get { return _bars; }
set
{
_bars= value;
NotifyPropertyChanged("Bars");
// snipped obvious INotifyPropertyChanged boilerplate code
}
}
}
C#视图模型:
<ListBox DataContext="{Binding Foos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding Main.SelectedFoo, Mode=TwoWay,
Source={StaticResource Locator},
UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding Main.SelectedFoo, Source={StaticResource Locator}}"/>
<ListBox ItemsSource="{Binding Main.SelectedFoo.Bars}" SelectedItem="{Binding Main.SelectedBar}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Right">
<!-- The binding requires "{Binding .}" because a path must be explicitly set for Two-Way binding,
even though {Binding .} is supposed to be identical to {Binding} -->
<TextBox Text="{Binding Path=. , UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
private ObservableCollection<Foo> _barList = new ObservableCollection<Foo>();
private const string BardListPN = "FooList";
public ObservableCollection<Foo> FooList
{
get { return _fooList; }
set
{
if (_fooList == value)
{
return;
}
var oldValue = _fooList;
_fooList = value;
RaisePropertyChanged(FooListPN);
}
}
private Foo _selectedFoo;
private const string SelectedFooPN = "SelectedFoo";
public Foo SelectedFoo
{
get { return _selectedFoo; }
set
{
if (_selectedFoo == value)
{
return;
}
var oldValue = _selectedFoo;
_selectedFoo = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedFooPN);
}
}
public const string SelectedBarPN = "SelectedBar";
private string _selectedBar = "";
public string SelectedBar
{
get
{
return _selectedBar;
}
set
{
if (_selectedBar == value)
{
return;
}
var oldValue = _selectedBar;
_selectedBar = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedBarPN);
}
}
public class Foo
{
public ICollection<string> Bars
{
get { return _bars; }
set
{
_bars= value;
NotifyPropertyChanged("Bars");
// snipped obvious INotifyPropertyChanged boilerplate code
}
}
}
private observedcollection\u barList=new observedcollection();
私有常量字符串BardListPN=“傻瓜”;
公众观察收集愚人
{
获取{return}
设置
{
如果(_傻瓜==值)
{
返回;
}
var oldValue=\u傻瓜;
_愚人=价值;
RaisePropertyChanged(愚人党);
}
}
私人食品(选择食品);;
私有常量字符串SelectedFooPN=“SelectedFoo”;
公共食物选择食物
{
获取{return\u selectedFoo;}
设置
{
如果(_selectedFoo==值)
{
返回;
}
var oldValue=_selectedFoo;
_selectedFoo=值;
//更新绑定,无广播
RaisePropertyChanged(已选择Foopn);
}
}
public const string SelectedBarPN=“SelectedBar”;
私有字符串_selectedBar=“”;
公共字符串选择栏
{
得到
{
返回_selectedBar;
}
设置
{
如果(_selectedBar==值)
{
返回;
}
var oldValue=_selectedBar;
_selectedBar=值;
//更新绑定,无广播
RaisePropertyChanged(已选择BARPN);
}
}
C#型号:
<ListBox DataContext="{Binding Foos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding Main.SelectedFoo, Mode=TwoWay,
Source={StaticResource Locator},
UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding Main.SelectedFoo, Source={StaticResource Locator}}"/>
<ListBox ItemsSource="{Binding Main.SelectedFoo.Bars}" SelectedItem="{Binding Main.SelectedBar}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Right">
<!-- The binding requires "{Binding .}" because a path must be explicitly set for Two-Way binding,
even though {Binding .} is supposed to be identical to {Binding} -->
<TextBox Text="{Binding Path=. , UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
private ObservableCollection<Foo> _barList = new ObservableCollection<Foo>();
private const string BardListPN = "FooList";
public ObservableCollection<Foo> FooList
{
get { return _fooList; }
set
{
if (_fooList == value)
{
return;
}
var oldValue = _fooList;
_fooList = value;
RaisePropertyChanged(FooListPN);
}
}
private Foo _selectedFoo;
private const string SelectedFooPN = "SelectedFoo";
public Foo SelectedFoo
{
get { return _selectedFoo; }
set
{
if (_selectedFoo == value)
{
return;
}
var oldValue = _selectedFoo;
_selectedFoo = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedFooPN);
}
}
public const string SelectedBarPN = "SelectedBar";
private string _selectedBar = "";
public string SelectedBar
{
get
{
return _selectedBar;
}
set
{
if (_selectedBar == value)
{
return;
}
var oldValue = _selectedBar;
_selectedBar = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedBarPN);
}
}
public class Foo
{
public ICollection<string> Bars
{
get { return _bars; }
set
{
_bars= value;
NotifyPropertyChanged("Bars");
// snipped obvious INotifyPropertyChanged boilerplate code
}
}
}
公共类Foo
{
公共ICollection酒吧
{
获取{返回_条;}
设置
{
_条=值;
NotifyPropertyChanged(“酒吧”);
//剪下明显的InotifyProperty更改样板代码
}
}
}
我的问题是,Bar
集合中字符串的文本框没有设置任何更改。当选定的Foo
更改为不同的Foo
并返回时,将显示原始的条
有人能告诉我我做错了什么吗?这看起来应该简单得多。谢谢
更新:我已经按照Tri Q的建议更改了代码,但是对文本框所做的更改并没有反映在属性本身中。有什么想法吗?在这个例子中,我采用的Foo模型类已经简化,但是省略的代码可能是问题的罪魁祸首。让我解释一下
Foo还需要实现INotifyPropertyChanged,以便让Listbox知道何时初始化了Bars集合,这完全取决于何时初始化它
假设您在Foo的构造函数中初始化了Bars,则会导致Listbox ItemsSource绑定到有效的Bars集合
public Foo()
{
Bars = new ObservableCollection<string>();
...
}
其次,为itemsource
设置Mode=“TwoWay”
没有意义。ItemsSource=“{Binding Main.SelectedFoo.bar,Mode=TwoWay}”
最后,您不需要为数据模板
设置数据类型
。DataType=“{x:Type System:String}”真棒的答案!非常感谢你提供的额外信息。是的,正如您可以清楚地看到的,我仍在学习WPF和MVVM,我真诚地感谢您的评论。我会试试你的建议。有一点需要注意:我绑定文本框的方式是,需要一个路径,因为模式是TwoWay
(默认情况下也是如此),我在XAML注释中注意到了这一点。这似乎是将文本框
绑定到集合中当前项的唯一方法。