wpf ListBox selectedItem 开始工作但设置在 MVVM 中不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16537270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:47:24  来源:igfitidea点击:

ListBox selectedItem get working but set not working in MVVM

c#wpfmvvmlistbox

提问by fhnaseer

I am working on a WPF application and following MVVM. In my view there is a grid view which contains different columns. One of these column is a ListBox. Now problem is that for the ListBox column, SelectedItem get works fine but set doesn't.

我正在开发 WPF 应用程序并关注 MVVM。在我看来,有一个包含不同列的网格视图。这些列之一是列表框。现在的问题是对于 ListBox 列, SelectedItem get 工作正常但 set 没有。

Here is my View code

这是我的查看代码

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

In my ViewModel, I have Main ViewModel class, which contains a list of Items. Item class contains name, a list of actions and selected action.

在我的 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; }
    }
}

Now SelectedItem for Items list works fine. But SelectedItem insde Item class for Actions doesn't work completely. I inserted breakpoints on getter and setter of SelectedAction. get breakpoint hits. But if I select an action from the UI then set breakpoint for SelectedAction doesn't get hit.

现在,项目列表的 SelectedItem 工作正常。但是 SelectedItem insde Item 类的 Actions 不能完全工作。我在 SelectedAction 的 getter 和 setter 上插入了断点。获得断点命中。但是,如果我从 UI 中选择一个操作,则不会为 SelectedAction 设置断点。

What's the problem.

有什么问题。

View

看法

When I select Archive Project or Restore Project, setter of SelectedAction doesn't get called.

当我选择存档项目或恢复项目时,不会调用 SelectedAction 的设置器。

NOTE:I have removed unnecessary information like loading data in lists, implementation of INotifyOfPropertyChanged etc.

注意:我删除了不必要的信息,例如在列表中加载数据、INotifyOfPropertyChanged 的​​实现等。

采纳答案by fhnaseer

Here is the fix. We need to set UpdateSourceTrigger for the listbox for selectedItem,

这是修复。我们需要为 selectedItem 的列表框设置 UpdateSourceTrigger,

<DataTemplate>
   <ListBox DisplayMemberPath="Name" ItemsSource="{Binding Actions}" SelectedItem="{Binding SelectedAction, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>

回答by user1098580

I don't know if it is your case but since you've said that you have cut some information I'll try to answer.

我不知道是不是你的情况,但既然你说你削减了一些信息,我会试着回答。

this happen to me when I add a custum template to a ListBox or ListView and that the controls within the ListBoxItem handle the click event themselve.

当我将自定义模板添加到 ListBox 或 ListView 并且 ListBoxItem 中的控件自己处理单击事件时,就会发生这种情况。

For example if you have a radio button like this

例如,如果您有一个这样的单选按钮

<ListBox ItemsSource="{Binding List}" SelectedItem="{Binding item}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <RadioButton Content="{Binding Name}" GroupName="groupName">
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

The SelectedItem will not be set when you actualy click on the radio button because the radio button will handle the click event and will not bubble it up so the ListBox may change it's selection.

当您实际单击单选按钮时,不会设置 SelectedItem,因为单选按钮将处理单击事件并且不会冒泡,因此 ListBox 可能会更改它的选择。

You have to make sure that the ListBox get the event and that the controls in the template react accordingly. in this case you'll have to do something like this.

您必须确保 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>

回答by Jehof

You need to specify a TwoWay-Binding on the SelectedItem. Otherwise are changes made on the UI not passed to your viewmodel.

您需要在 SelectedItem 上指定一个双向绑定。否则对 UI 所做的更改不会传递到您的视图模型。

SelectedItem="{Binding SelectedAction, Mode=TwoWay}"

回答by Erno

The SelectedItem property of the MyViewModel class does not use the INotifyPropertyChanged interface by raising the PropertyChanged event when the setter changed its value:

MyViewModel 类的 SelectedItem 属性不会通过在 setter 更改其值时引发 PropertyChanged 事件来使用 INotifyPropertyChanged 接口:

public Item SelectedItem
{
    get { return _selectedItem; }
    set 
    {
        if(value != _selectedItem)
        {
            _selectedItem= value; 
            OnPropertyChanged("SelectedItem");
        }
    }
}

You should do this for all properties in all ViewModels.

您应该对所有 ViewModel 中的所有属性执行此操作。

回答by Der_Meister

Look into Output Window in VS. Probably your property type differs from item type.

查看 VS 中的输出窗口。可能您的属性类型与项目类型不同。

回答by Dunge

Not only is "Erno de Weerd" answer right, you need to notify the property change on your selected properties, but also WPF DataGrid are the most bugged control offered by Microsoft in relation to MVVM.

不仅“Erno de Weerd”的答案是正确的,您需要通知所选属性的属性更改,而且 WPF DataGrid 是 Microsoft 提供的与 MVVM 相关的漏洞最多的控件。

You will notice that the SelectedItem property of the innerlist WILL update, only when you change the selection of the outer list. To refresh it live when the inner list selection change, you need to change your binding on the list to add this:

您会注意到内部列表的 SelectedItem 属性将更新,仅当您更改外部列表的选择时。要在内部列表选择更改时实时刷新它,您需要更改列表上的绑定以添加以下内容:

SelectedItem="{Binding SelectedAction, UpdateSourceTrigger=PropertyChanged}"

SelectedItem="{Binding SelectedAction, UpdateSourceTrigger=PropertyChanged}"

This is not needed when the listbox is not embedded in a datagrid column.

当列表框未嵌入到数据网格列中时,不需要这样做。

回答by blindmeis

i dont know if i'm on the right way, but did you try to wrap your string in a class?

我不知道我是否走对了路,但是您是否尝试将字符串包裹在课堂中?

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