删除SelectedItem时WPF DisplayMemberPath不更新

时间:2015-02-23 13:56:42

标签: wpf mvvm combobox

我尽可能地简化了这个问题。基本上我覆盖了组合框的“空”值。因此,如果选中的项目被删除,它将恢复为“(null)”。不幸的是,这是错误的行为,我点击删除,ObservableCollection项被删除,因此更新了属性绑定,并按预期返回“(null)”项。但组合框外观显示空白。然而它所受的价值是正确的...这个问题可以用下面的代码再现。

要重现此问题,请选择一个项目,然后按“删除”。请注意,此时将调用以下行(当您删除所选项目时)。所以它是断点的好地方。

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

结果:

Result after pressing remove

1 个答案:

答案 0 :(得分:4)

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

问题是(是),DisplayMemberPathSelectedItem一起使用。 DisplayMemberPath并未提供有关已更改SelectedItem的f ***。

要解决此问题,您需要做的是两件事:

首先,在RemoveSelected方法中,将Selected属性设置为null(强制更新绑定):

public void RemoveSelected()
{
    Items.Remove(Selected);
    Selected = null;
}

然后,在XAML定义中,更改绑定属性:

<ComboBox ItemsSource="{Binding Items}"
          SelectedValue="{Binding Selected, Mode=TwoWay}"
          DisplayMemberPath="Name"/>

绑定SelectedValue属性将正确更新ComboBox中显示的文本。