实现 BindingList<T>

3

我正在尝试了解BindingList,因为我相信它将帮助我完成正在进行的项目。

目前,我有一个对象类(ScannedImage),它是一个类(HashedImage)的子类型,该类又是本地.Net对象(Image)的子类型。没有理由我不能将这两个子类型合并在一起。我只是将先前构造的对象子类型化,但现在将在RDB中存储我的ScannedImage对象(不是技术上的,只有详细信息和可能的缩略图)。

此外,对象类具有我的自定义类型(关键字)的成员类型。我正在使用自定义datagridview来呈现这些对象,但是正在处理对ScannedImage对象的所有更改的代码是我的自己的。正如您可能想象的那样,我有很多在这些基本类型中发生的事件要处理。

因此,如果我更改了我的对象以实现INotifyPropertyChanged,那么对象集合(实现BindingList)是否会接收到对ScannedImage对象的更改通知?

此外,如果关键字实现了INotifyPropertyChanged,那么通过ScannedImage对象,BindingList是否可以访问更改?

如果这听起来很新手,我很抱歉。我最近才发现BindingList,而且没有接受过C#编程的正式培训-所以在这方面前进很困难。

此外,如果有人有好的参考资料,我将感激链接。显然,我已经浏览了MSDN库。我在网上找到了一些不错的链接,但是似乎很多人现在正在使用WPF和ObservableCollection。

我的项目基于Winforms和.Net3.5框架。

TIA


你是正确的。标题应该是“实现IBindingList”,或者正如你所指出的那样(我应该)“使用BindingList<T>与实现INotifyPropertChanged的对象类”。 - EtherealMonkey
1个回答

1
我来回答你的两个问题:
如果我将我的对象更改为实现INotifyPropertyChanged,那么实现BindingList的对象集合会收到有关ScannedImage对象更改的通知吗?
如果你实际上在System.ComponentModel中使用BindingList类,那么它确实包含特殊情况代码,用于实现INotifyPropertyChanged的元素。列表将看到属性更改并发送通知。
但是,你明确询问“实现BindingList”,这是微妙的不同。你不能实现一个类。但是有一个接口IBindingList,你可以用自己的类来实现它。如果你选择这条路,那么当你编写列表类时,就需要确保你监视属性更改通知。

通常情况下,您不需要创建自己的IBindingList实现;只需使用BindingList<T>来包装现有列表即可。

另外,如果关键字(Keywords)实现了INotifyPropertyChanged,那么通过ScannedImage对象,BindingList是否可以访问更改?

不行。 BindingList<T>只查看列表中的特定对象,它无法扫描所有依赖项并监视图形中的所有内容(如果可能的话,这也不总是一个好主意)。

如果您想要接收通知,您需要更新ScannedImage类以检查来自Keywords对象的属性更改通知,然后响应地触发自己的PropertyChanged事件。

例如:

public class ScannedImage : INotifyPropertyChanged
{
    private Keywords keywords;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            PropertyChangedEventArgs e = new 
                PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    private void KeywordsChanged(object sender, PropertyChangedEventArgs e)
    {
        OnPropertyChanged("Keywords");
    }

    private void SetKeywords(Keywords newKeywords)
    {
        Keywords oldKeywords = this.keywords;
        this.keywords = null;
        if (oldKeywords != null)
            oldKeywords.PropertyChanged -= KeywordsChanged;
        this.keywords = newKeywords;
        if (newKeywords != null)
            newKeywords.PropertyChanged += KeywordsChanged;
    }

    public Keywords Keywords
    {
        get { return keywords; }
        set { SetKeywords(value); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class Keywords : INotfifyPropertyChanged { ... }

我希望你理解这里正在做什么。所有者ScannedImage自动挂钩其内部的Keywords类中的PropertyChanged事件,并引发单独的属性更改事件,说Keywords已更改。 这样,绑定列表和其他数据绑定控件将在关键字更改时接收通知。


好的,还有一个问题(我想我会尝试,但是我会为后人提问...)我的关键字类可以有多个PropertyChangedEventHandler吗?我之所以问这个问题,是因为我想从列表中添加和删除单个关键字。虽然您提供的方法可以工作,但我通常更喜欢将单个关键字添加到列表中,而不是将其视为“不可变”的。实际上,算了吧 - 我(认为我)刚刚意识到答案。在KeywordsChanged中,我应该只测试发送器并根据类型或事件参数执行开关 - 对吗? - EtherealMonkey
也对,这很有道理。我感谢你的例子。问题现在清晰多了! - EtherealMonkey
@Ethereal:抱歉,我不太明白你在第一个问题中的问题。我想不出为什么你需要在这里测试发送者的任何原因。我认为你可能遗漏了一些东西,但我不确定是什么;你认为 += KeywordsChanged 行实际上会触发事件吗?它不会,它只是为当 Keywords 的属性更改时(由该类自己实现的属性更改事件确定)连接事件处理程序。整个结构专门为具有自己的 PropertyChanged 事件的可变 Keywords 类设计。 - Aaronaught
@Aaronaught对于造成任何困惑,我感到非常抱歉。我只是觉得SetKeywords()函数将Keywords类视为“不可变”的,因为每次调用它都会替换整个对象。现在我想起来了,我将把Keywords对象视为List <Keyword>。所以,算了吧... 我知道该如何处理它;-) - EtherealMonkey
实际上,这是ImageKeywordList的当前声明: public class ImageKeyWordList : IList<string> - EtherealMonkey
而且,你的回答仍然非常有帮助。我花了很多时间寻找示例和文档,却忽略了一些非常简单的东西。让ScannedImage类代表ImageKeyWordList引发通知。我认为我可能需要对BindingList<T>进行子类型化,因为我将为每个BindingList缓存一个GUID,但我仍然明白我所错过的东西。非常感谢你的帮助。 - EtherealMonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接