Элемент управления ListBox сделать работает, но установить не работает в MVVM
Я работаю над приложением WPF и следую MVVM. На мой взгляд, существует сеточное представление, которое содержит различные столбцы. Одним из таких столбцов является список. Теперь проблема в том, что для столбца ListBox SelectedItem get работает нормально, а set-нет.
Вот мой код вида
<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, который содержит список элементов. Класс элемента содержит имя, список действий и выбранное действие.
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; }
}
}
Теперь SelectedItem для списка элементов работать отлично. Но элемент внутри элемента класса за действия, не работает. Я вставил точки останова на геттере и сеттере SelectedAction. получить точки останова хитов. Но если я выбираю действие из пользовательского интерфейса, то установить точку останова для SelectedAction не попадает.
В чем проблема?

Когда я выбираю архивировать проект или восстановить проект, setter SelectedAction не вызывается.
Примечание: я удалил ненужную информацию, такую как загрузка данные в списках, реализация INotifyOfPropertyChanged и т.д.
7 ответов:
Я не знаю, ваше ли это дело, но поскольку вы сказали, что сократили некоторую информацию, я попытаюсь ответить.
Это происходит со мной, когда я добавляю шаблон 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 не будет установлен, когда вы фактически нажмете на переключатель, потому что переключатель будет обрабатывать событие click и не будет пузырь его вверх, так что список может изменить его выбор.
Вы должны убедиться, что 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>
Вам нужно указать привязку TwoWay к SelectedItem. В противном случае изменения, внесенные в пользовательский интерфейс, не передаются в viewmodel.
SelectedItem="{Binding SelectedAction, Mode=TwoWay}"
Свойство SelectedItem класса MyViewModel не использует интерфейс INotifyPropertyChanged, вызывая событие PropertyChanged при изменении его значения задатчиком:
public Item SelectedItem { get { return _selectedItem; } set { if(value != _selectedItem) { _selectedItem= value; OnPropertyChanged("SelectedItem"); } } }Вы должны сделать это для всех свойств во всех ViewModels.
Вот исправление. Нам нужно установить UpdateSourceTrigger для списка для selectedItem,
<DataTemplate> <ListBox DisplayMemberPath="Name" ItemsSource="{Binding Actions}" SelectedItem="{Binding SelectedAction, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate>
Я не знаю, на правильном ли я пути, но вы пытались обернуть свою строку в классе?
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; } } }
Не только" Erno de Weerd " ответ правильный, вам нужно уведомить об изменении свойства на выбранных вами свойствах, но и WPF DataGrid - это самый прослушиваемый элемент управления, предлагаемый Microsoft в отношении MVVM.
Вы заметите, что свойство SelectedItem внутреннего списка будет обновляться только при изменении выбора внешнего списка. Чтобы обновить его в реальном времени при изменении выбора внутреннего списка, вам нужно изменить привязку к списку, чтобы добавить следующее:
SelectedItem= " {Привязка SelectedAction, UpdateSourceTrigger=PropertyChanged}"
Это не требуется, если список не встроен в столбец datagrid.
Comments