删除 SelectedItem 时 WPF DisplayMemberPath 不更新
WPF DisplayMemberPath not Updating when SelectedItem is removed
我已经尽可能地简化了这个问题。基本上我覆盖了组合框的 "null" 值。因此,如果项目 selected 被删除,它会恢复为“(null)”。不幸的是,这是错误的行为,我点击删除,ObservableCollection 项目被删除,因此 属性 绑定被更新,并且它 returns 预期的“(null)”项目。但组合框外观显示空白。然而它绑定的值是正确的......这个问题可以用下面的代码重现。
要重现此问题,您 select 一个项目,然后点击删除。请注意,此时将调用以下行(当您删除 selected 项目时)。所以断点的好地方。
if (m_Selected == null)
{
return Items[0]; //items 0 is ItemNull
}
另请注意,我已尝试通过在 DisplayMemberPath 上强制执行 属性 更新来修复它。这没有用。
MainWindow.xaml
<Window x:Class="WPFCodeDump.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding Selected, Mode=TwoWay}" DisplayMemberPath="Name"></ComboBox>
<Button Click="ButtonBase_OnClick">Remove Selected</Button>
</StackPanel>
</Window>
MainWindowViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace WPFCodeDump
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
//Item class
public class Item : ViewModelBase
{
public Item(string name)
{
m_Name = name;
}
public string Name
{
get { return m_Name; }
}
private string m_Name;
public void ForcePropertyUpdate()
{
OnPropertyChanged("Name");
}
}
//Item class
public class ItemNull : Item
{
public ItemNull()
: base("(null)")
{
}
}
class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
m_Items.Add(new ItemNull());
for (int i = 0; i < 10; i++)
{
m_Items.Add(new Item("TestItem" + i));
}
Selected = null;
}
//Remove selected command
public void RemoveSelected()
{
Items.Remove(Selected);
}
//The item list
private ObservableCollection<Item> m_Items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items
{
get { return m_Items; }
}
//Selected item
private Item m_Selected;
public Item Selected
{
get
{
if (m_Selected == null)
{
return Items[0]; //items 0 is ItemNull
}
return m_Selected;
}
set
{
m_Selected = value;
OnPropertyChanged();
if(m_Selected!=null) m_Selected.ForcePropertyUpdate();
}
}
}
}
MainWindow.xaml.cs
using System.Windows;
namespace WPFCodeDump
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
((MainWindowViewModel) DataContext).RemoveSelected();
}
}
}
结果:
您在那里发现了一个很好的绑定问题。但一如既往,这是我们的错,不是他们的:)
问题是,使用 DisplayMemberPath
和 SelectedItem
。
DisplayMemberPath
根本不在乎 SelectedItem
.
要解决此问题,您必须做两件事:
首先,在 RemoveSelected
方法中,将 Selected
属性 设置为空(强制更新绑定):
public void RemoveSelected()
{
Items.Remove(Selected);
Selected = null;
}
然后,在 XAML 定义中,更改绑定 属性:
<ComboBox ItemsSource="{Binding Items}"
SelectedValue="{Binding Selected, Mode=TwoWay}"
DisplayMemberPath="Name"/>
绑定 SelectedValue
属性 将正确更新 ComboBox
中显示的文本。
我已经尽可能地简化了这个问题。基本上我覆盖了组合框的 "null" 值。因此,如果项目 selected 被删除,它会恢复为“(null)”。不幸的是,这是错误的行为,我点击删除,ObservableCollection 项目被删除,因此 属性 绑定被更新,并且它 returns 预期的“(null)”项目。但组合框外观显示空白。然而它绑定的值是正确的......这个问题可以用下面的代码重现。
要重现此问题,您 select 一个项目,然后点击删除。请注意,此时将调用以下行(当您删除 selected 项目时)。所以断点的好地方。
if (m_Selected == null)
{
return Items[0]; //items 0 is ItemNull
}
另请注意,我已尝试通过在 DisplayMemberPath 上强制执行 属性 更新来修复它。这没有用。
MainWindow.xaml
<Window x:Class="WPFCodeDump.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding Selected, Mode=TwoWay}" DisplayMemberPath="Name"></ComboBox>
<Button Click="ButtonBase_OnClick">Remove Selected</Button>
</StackPanel>
</Window>
MainWindowViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace WPFCodeDump
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
//Item class
public class Item : ViewModelBase
{
public Item(string name)
{
m_Name = name;
}
public string Name
{
get { return m_Name; }
}
private string m_Name;
public void ForcePropertyUpdate()
{
OnPropertyChanged("Name");
}
}
//Item class
public class ItemNull : Item
{
public ItemNull()
: base("(null)")
{
}
}
class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
m_Items.Add(new ItemNull());
for (int i = 0; i < 10; i++)
{
m_Items.Add(new Item("TestItem" + i));
}
Selected = null;
}
//Remove selected command
public void RemoveSelected()
{
Items.Remove(Selected);
}
//The item list
private ObservableCollection<Item> m_Items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items
{
get { return m_Items; }
}
//Selected item
private Item m_Selected;
public Item Selected
{
get
{
if (m_Selected == null)
{
return Items[0]; //items 0 is ItemNull
}
return m_Selected;
}
set
{
m_Selected = value;
OnPropertyChanged();
if(m_Selected!=null) m_Selected.ForcePropertyUpdate();
}
}
}
}
MainWindow.xaml.cs
using System.Windows;
namespace WPFCodeDump
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
((MainWindowViewModel) DataContext).RemoveSelected();
}
}
}
结果:
您在那里发现了一个很好的绑定问题。但一如既往,这是我们的错,不是他们的:)
问题是,使用 DisplayMemberPath
和 SelectedItem
。
DisplayMemberPath
根本不在乎 SelectedItem
.
要解决此问题,您必须做两件事:
首先,在 RemoveSelected
方法中,将 Selected
属性 设置为空(强制更新绑定):
public void RemoveSelected()
{
Items.Remove(Selected);
Selected = null;
}
然后,在 XAML 定义中,更改绑定 属性:
<ComboBox ItemsSource="{Binding Items}"
SelectedValue="{Binding Selected, Mode=TwoWay}"
DisplayMemberPath="Name"/>
绑定 SelectedValue
属性 将正确更新 ComboBox
中显示的文本。