我正在研究WPF应用程序并关注MVVM。在我看来,有一个包含不同列的网格视图。其中一列是ListBox。现在的问题是,对于ListBox列,SelectedItem get工作正常但设置不了。
这是我的查看代码
<DataGrid ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" />
<DataGridTemplateColumn Header="Actions">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListBox DisplayMemberPath="Name" ItemsSource="{Binding Actions}" SelectedItem="{Binding SelectedAction}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
在我的ViewModel中,我有Main ViewModel类,其中包含Items列表。 Item类包含名称,操作列表和选定的操作。
public class MyViewModel : INotifyOfPropertyChanged
{
private ObservableCollection<Item> _items;
public ObservableCollection<Item> Items
{
get { return _items?? (_items= new ObservableCollection<Item>); }
}
private Item _selectedItem;
public Item SelectedItem
{
get { return _selectedItem; }
set { _selectedItem= value; }
}
}
public class Item : INotifyOfPropertyChanged
{
public string Name;
private ObservableCollection<string> _actions;
public ObservableCollection<string> Actions
{
get { return _actions?? (_actions= new ObservableCollection<string>); }
}
private string _selectedAction;
public string SelectedAction
{
get { return _selectedAction; }
set { _selectedAction = value; }
}
}
Now SelectedItem for Items列表工作正常。但是SelectedItem为动作提供的Item类并不完全有效。我在SelectedAction的getter和setter上插入了断点。得到断点命中。但是如果我从UI中选择一个动作,那么为SelectedAction设置断点并不会被击中。
问题是什么。
当我选择Archive Project或Restore Project时,SelectedAction的setter不会被调用。
注意:我删除了不必要的信息,例如在列表中加载数据,实现INotifyOfPropertyChanged等。
答案 0 :(得分:8)
我不知道是不是你的情况,但既然你说你已经删除了一些信息,我会尽力回答。
当我将一个custum模板添加到ListBox或ListView并且ListBoxItem中的控件处理click事件时,这种情况发生在我身上。例如,如果您有这样的单选按钮
<ListBox ItemsSource="{Binding List}" SelectedItem="{Binding item}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding Name}" GroupName="groupName">
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
当您实际点击单选按钮时,将不会设置SelectedItem,因为单选按钮将处理单击事件并且不会将其冒泡,因此ListBox可能会更改它的选择。
您必须确保ListBox获取事件,并且模板中的控件会相应地做出反应。在这种情况下,你将不得不做这样的事情。
<ListBox ItemsSource="{Binding List}" SelectedItem="{Binding Item}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding Name}" IsHitTestVisible="False">
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
</Style>
</RadioButton.Style>
</RadioButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
答案 1 :(得分:3)
您需要在SelectedItem上指定TwoWay-Binding。否则,在UI上进行的更改未传递给您的viewmodel。
SelectedItem="{Binding SelectedAction, Mode=TwoWay}"
答案 2 :(得分:2)
当setter更改其值时,MyViewModel类的SelectedItem属性不会通过引发PropertyChanged事件来使用INotifyPropertyChanged接口:
public Item SelectedItem
{
get { return _selectedItem; }
set
{
if(value != _selectedItem)
{
_selectedItem= value;
OnPropertyChanged("SelectedItem");
}
}
}
您应该对所有ViewModel中的所有属性执行此操作。
答案 3 :(得分:1)
这是修复。我们需要为selectedItem的列表框设置UpdateSourceTrigger,
<DataTemplate>
<ListBox DisplayMemberPath="Name" ItemsSource="{Binding Actions}" SelectedItem="{Binding SelectedAction, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
答案 4 :(得分:0)
我不知道我是不是正确的方式,但你是否尝试将你的字符串包装在课堂上?
public class Item : INotifyOfPropertyChanged
{
public string Name;
private ObservableCollection<MyActionString> _actions;
public ObservableCollection<MyActionString> Actions
{
get { return _actions?? (_actions= new ObservableCollection<MyActionString>); }
}
private MyActionString _selectedAction;
public MyActionString SelectedAction
{
get { return _selectedAction; }
set { _selectedAction = value; }
}
}
答案 5 :(得分:0)
查看VS中的输出窗口。可能您的房产类型与项目类型不同。
答案 6 :(得分:0)
不仅是&#34; Erno de Weerd&#34;回答正确,您需要通知所选属性的属性更改,但WPF DataGrid也是Microsoft提供的与MVVM相关的最多错误控件。
只有在更改外部列表的选择时,才会注意到内部列表的SelectedItem属性将更新。要在内部列表选择更改时刷新它,您需要更改列表上的绑定以添加:
SelectedItem =&#34; {Binding SelectedAction, UpdateSourceTrigger = PropertyChanged }&#34;
当列表框未嵌入数据网格列时,不需要这样做。