Элемент управления 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 и т.д.

668   7  

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; }
}
}

Посмотрите в окно вывода в VS. вероятно, ваш тип свойства отличается от типа элемента.

Не только" Erno de Weerd " ответ правильный, вам нужно уведомить об изменении свойства на выбранных вами свойствах, но и WPF DataGrid - это самый прослушиваемый элемент управления, предлагаемый Microsoft в отношении MVVM.

Вы заметите, что свойство SelectedItem внутреннего списка будет обновляться только при изменении выбора внешнего списка. Чтобы обновить его в реальном времени при изменении выбора внутреннего списка, вам нужно изменить привязку к списку, чтобы добавить следующее:

SelectedItem= " {Привязка SelectedAction, UpdateSourceTrigger=PropertyChanged}"

Это не требуется, если список не встроен в столбец datagrid.

Comments

    Ничего не найдено.