【问题标题】:ObservableCollection<T> in Winforms and possible alternativesWinforms 中的 ObservableCollection<T> 和可能的替代方案
【发布时间】:2010-12-19 08:02:28
【问题描述】:

Winforms .net 3.5 应用程序。在我的应用程序中,我有一个看起来像这样的通用类:

public class FilterItem {
  public FilterItem() { }
  public string FilterProperty { get; set; }
  public bool FilterPropertyChecked { get; set; }
  public ComparitiveOperator FilterOperator { get; set; }
  public string FilterValue { get; set; }
}

当我想实现某种过滤器功能时,我会在所有对话框中使用它。因此,我使用在构造函数中传递的预填充List&lt;FilterItem&gt; 调用对话框表单。现在,当对话框加载时,它会遍历每个列表项并添加:

  1. 一个复选框
  2. 一个组合框
  3. 一个文本框

到 TableLayoutPanel 中的每一行。 Checkbox 从FilterProperty 获取其文本属性,从FilterPropertyChecked 获取其Checked 状态...Combobox 从FilterOperator 获取其绑定...而Textbox 从FilterValue 获取其文本值。

注意我只是说得到。我想做的是在它们的属性必须更改的控件时自动更新这些属性。我听说过 ObservableCollection&lt;T&gt;,但在添加 System.Collections.ObjectModel 命名空间后,我似乎无法在 Winforms 中“访问”它。

实现这一点的最佳方法是什么。 BindingList 与 INotifyPropertyChanged??我不是后者的专家,非常感谢一些指示 - 如果这是我应该走的路。

谢谢你!

编辑:

好的,让我发布一些代码来展示我认为我应该做什么:)。我知道我需要在我的 FilterItem 类上实现INotifyPropertyChanged,所以(仅针对 FilterValue 部分):

public class FilterItem : INotifyPropertyChanged {
    public FilterItem() { }
    public string FilterProperty { get; set; }
    public bool FilterPropertyChecked { get; set; }
    public ComparitiveOperator FilterOperator { get; set; }

    private string _FilterValue;
    public string FilterValue {
        get { return this._FilterValue; }
        set {
            if (this._FilterValue != value) {
                this._FilterValue = value;
                this.OnFilterValueChanged();
            }
        }
    }

    #region INotifyPropertyChanged Members
    protected void OnFilterValueChanged() {
        var handler = this.PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs("FilterValue"));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion
}

现在它应该全部放在我的 Form_Load 中(这仅适用于文本框部分,我省略了 Checbox 和 ComboBox),如下所示:

private List<FilterItem> FilterList; // <-- this gets assigned to in the constructor

private void dlgFilterData_Load(object sender, EventArgs e) {
    foreach (FilterItem item in FilterList) {
        txt = new TextBox();
        txt.DataBindings.Add("Text", item, "FilterValue", false, DataSourceUpdateMode.OnPropertyChanged);
        txt.Dock = DockStyle.Fill;
    }
}

文本框的数据绑定 DataSource 是 FilterItem 'item'。但是现在我的 Visual Studio IDE 似乎有问题,所以不能尝试这个,但是当我启动并运行它时会。我现在想知道的是:此设置能否成功帮助我的个人FilterItems 在其分配的 Control 各自的属性发生更改时自动更新??

【问题讨论】:

  • 我是否也应该使用 BindingList 而不是普通的 List

标签: winforms observablecollection inotifypropertychanged


【解决方案1】:

ObservableCollection 类位于 WindowsBase 程序集中,因此您需要将 WindowsBase 添加到项目引用中才能“访问”它。

话虽如此,我认为 ObservableCollection 不会给你想要的一切。当您添加或删除项目时,您的绑定控件会收到通知,但没有自动属性更改通知,这正是您想要的。

无论您最终使用哪种集合,我认为您在使用 INotifyPropertyChanged 时都走在了正确的轨道上。下面是一个实现 INotifyPropertyChanged 的​​简单示例:

class Foo : INotifyPropertyChanged
{
    #region Bar property

    private string _bar;
    public string Bar
    {
        get { return _bar; }
        set
        {
            if (_bar != value)
            {
                _bar = value;

                OnPropertyChanged("Bar");
            }
        }
    }

    #endregion

    protected void OnPropertyChanged(string name)
    {
        var handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

基本上,只要对象的属性发生更改,就会触发 PropertyChanged 事件,并传递更改的属性的名称。

最后,所有这些都可能没有实际意义,因为您说过要更改对象属性的值以响应绑定到该属性的控件的更改。通常的 Windows 窗体数据绑定基础结构可以在没有 INotifyPropertyChanged 或任何其他接口的帮助下实现这一点。如果您需要从其他地方通知绑定控件您的对象属性的更改,则只需实现 INotifyPropertyChanged。

【讨论】:

  • 丹尼尔,非常感谢您的回复和代码!针对上述情况,我不太确定我是否完全理解你的最后一句话——你能帮我澄清一下吗?另外,我是否在文本框数据绑定的正确轨道上,并使用 BindingList 而不是 List? (抱歉,我的 VS IDE 仍在闪烁,但我认为它的一大堆愚蠢的插件会导致它崩溃。现在删除它们,所以希望有机会测试所有这些)。
  • 当您在对象和控件之间设置双向数据绑定(正常情况)时,框架将尝试更新其中一个以响应另一个的变化。数据绑定框架已经知道如何检测内置控件的属性何时发生更改,因此它可以更改数据源对象的绑定属性,而无需您提供任何进一步的帮助。另一方面,如果您在代码中更改数据源对象的属性值,除非您正确实现 INotifyPropertyChanged,否则框架不知道如何检测(并更新绑定的控件)。
  • 关于使用 BindingList 与 List:考虑到您是如何构建表单的,这没有区别。如果您将 FilterItem 对象的集合直接绑定到网格或列表框之类的东西,则 BindingList 会这样做,以便将项目添加到集合中会将相同的项目添加到网格/列表框,反之亦然。
  • 哇!刚从没有连接的 10 小时中恢复过来!感谢所有的投入,丹尼尔!我很高兴地告诉你,我上面描述的路线肯定对我有用,只是对你的代码进行了一些调整;)谢谢你的帮助,我完全理解你的最后 2 个 cmets!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多