删除 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();
        }
    }
}

结果:

您在那里发现了一个很好的绑定问题。但一如既往,这是我们的错,不是他们的:)

问题是,使用 DisplayMemberPathSelectedItemDisplayMemberPath 根本不在乎 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 中显示的文本。