【问题标题】:How IEQuatable<T> affect the behavior of comboboxIEQuatable<T> 如何影响组合框的行为
【发布时间】:2011-03-14 07:35:12
【问题描述】:

在处理组合框时,我发现了一个有线问题。 Xaml 看起来像这样

<ComboBox x:Name="cb" ItemsSource="{Binding MyEntity.Choices}" 
              SelectedItem="{Binding MyEntity.Choice,Mode=TwoWay}" 
              Height="25" 
              HorizontalAlignment="Stretch"
              VerticalAlignment="Top"/>

假设 Itemsource 与一个轴列表(对象)绑定,并且 selectedItem 是列表之一。

public partial class MainWindow : Window
{
    private ShaftsData shaftData;

    public ShaftsData ShaftData
    {
        get { return shaftData; }
        set { shaftData = value; }
    }
    public MainWindow()
    {
        ShaftData = new ShaftsData();
        InitializeComponent();
        txtBox.Text = "Default";
        this.DataContext = this;
        SetComboCollectionAndSelectedShaft();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        shaftData.ComboCollection = null;
    }

    private void SetComboCollectionAndSelectedShaft()
    {
        Collection<Shaft> myCollection = new Collection<Shaft>();
        for (int i = 1; i <= 5; ++i)
        {
            Shaft sh = new Shaft();
            sh.Id = i;
            sh.Name = string.Format("{0} {1} ", txtBox.Text, i);
            myCollection.Add(sh);
        }
        shaftData.ComboCollection = myCollection;
        shaftData.SelectedShaft = shaftData.ComboCollection[0];
    }
}

 public class ShaftsData : INotifyPropertyChanged
{
    private Collection<Shaft> _comboCollection;
    private  Shaft _selectedShaft;

    public Collection<Shaft> ComboCollection
    {
        get
        {
            return _comboCollection;

        }
        set
        {
            _comboCollection = value;
            OnPropertyChanged("ComboCollection");
        }
    }

    public Shaft SelectedShaft
    {
        get { return _selectedShaft; }
        set
        {
            _selectedShaft = value;
            OnPropertyChanged("SelectedShaft");
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

然后我尝试将此列表设为空(请参阅 Button_Click)。Combobox 正在调用 List 的每个对象的 .Equals 并比较最后一个 Selected 对象。 虽然我的期望是它不应该调用 .equals 并将 SelectedItem 设置为 null。

 public class Shaft
{
    private int _id;
    private string _name;

    public int Id {
        get { return _id; }
        set {
            _id = value;
        }
    }

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
        }
    }

    public override string ToString()
    {
        return _name;
    }

    public override bool Equals(object obj)
    {
        System.Diagnostics.Debug.WriteLine("Calling from object.Equals");
        Shaft shaft = obj as Shaft;
        if (null != shaft)
        {
            System.Diagnostics.Debug.WriteLine("Equals called for " + this.Name + ". Compared with " + shaft.Name);
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("Equals called for " + this + ". Compared with " + shaft);
        }
        return base.Equals(obj);
    }

现在,如果我在 Shaft 上实现 IEquatable,然后将 List 设置为 null,它可以正常工作。表示不会调用 .Eqauls & selectedItem 设置为 null。

新的实现

public class Shaft : IEquatable<Shaft>
    {
        private int _id;
        private string _name;

        public int Id {
            get { return _id; }
            set {
                _id = value;
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
            }
        }

        public override string ToString()
        {
            return _name;
        }

        public bool Equals(Shaft shaft)
        {
            System.Diagnostics.Debug.WriteLine("Calling from object.Equals");
           // Shaft shaft = obj as Shaft;
            if (null != shaft)
            {
                System.Diagnostics.Debug.WriteLine("Equals called for " + this.Name + ". Compared with " + shaft.Name);
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Equals called for " + this + ". Compared with " + shaft);
            }
            return base.Equals(shaft);
        }
    }
}

这表明即使列表为空,组合框也不会释放绑定到 Itemsource 的对象。 直到我们实现 IEquatable。

知道为什么会这样吗?

【问题讨论】:

  • 你必须更具体。不能完全理解你在说什么,尤其是为什么 ComboBox 调用 Equals。
  • @Stephen 我的问题是为什么即使我将组合框设置为空,组合框也不会释放 ItemsSource 中存在的对象?我找到了一种解决方法,如果我实现 IEquatable,那么它工作正常,但不知道为什么会出现这种行为。

标签: wpf combobox system.componentmodel


【解决方案1】:

Button_Click 上的行为对于两种实现来说是相同的。如果您没有在第二种情况下覆盖它,您怎么知道没有对 Object.Equals 的调用?

至于不“释放”对象,这看起来是 WPF 的一个已知问题:http://support.microsoft.com/kb/938416

作为一种解决方法,您可以执行以下操作之一:

  • 调用 Collection.Clear 方法,而不是将集合引用设置为 null
  • 使用 ObservableCollection 代替 Collection

【讨论】:

  • 我知道没有调用 Object.Equals(当我使用 IEquatable 时),因为我在 Equals 中使用了调试点。我也用 ObservableCollection 测试过,行为是一样的。我也看过微软的文章。它主要谈论绑定 PropertyDescriptor ,但在我的情况下,我绑定到属性。
  • @Deep:在第二种情况下,您没有 Object.Equals 方法,只有 IEquatable.Equals,因此无法在此处设置断点。如果您在第二种情况下尝试了一些其他代码,您可以展示一下吗?
  • @Deep:当您绑定到常规属性时,WPF 会在内部使用 PropertyDescriptor,这就是为什么文章会讨论它。
  • 我已经老旧地解释了你关于 object.equals 的问题。实际上,当我实现 IEquatable 时,我并没有覆盖 Object.Equals。如果我们正在实现 IEquatable,是否需要覆盖 Object.Equals?
  • @Deep:嗯,提供 Object.Equals、IEquatable 和运算符 '==' 和 '!=' 的一致实现是一个很好的做法。无论如何,问题是如果你没有实现它,你怎么知道在第二种情况下没有调用 Object.Equals?实际上,两种情况下的行为几乎相同。但是,在这种情况下,对象释放无论如何都与相等实现无关。该问题是由知识库文章中描述的原因引起的。
猜你喜欢
  • 2011-06-19
  • 2020-06-30
  • 2018-09-19
  • 2015-08-06
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2016-04-24
  • 1970-01-01
相关资源
最近更新 更多