views:

340

answers:

1

I am trying to learn more about BindingList because I believe that it will help me with a project that I am working on.

Currently, I have an object class (ScannedImage) that is a subtype of a class (HashedImage) that subtypes a native .Net object (Image). There is no reason why I couldn't move the two subtypes together. I am simply subtyping an object that I had previously constructed, but I will now be storing my ScannedImage object in an RDB (well, not technically - only the details and probably the thumbnail).

Also, the object class has member types that are my own custom types (Keywords). I am using a custom datagridview to present these objects, but am handling all changes to the ScannedImage object with my own code. As you can probably imagine, I have quite a few events to handle that occur in these base types.

So, if I changed my object to implement INotifyPropertyChanged, would the object collection (implementing BindingList) receive notifications of changes to the ScannedImage object?

Also, if Keywords were to implement INotifyPropertyChanged, would changes be accessible to the BindingList through the ScannedImage object?

Sorry if this seems rather newbish. I only recently discovered the BindingList and not having formal training in C# programming - am having a difficult time moving forward with this.

Also, if anyone has any good reference material, I would be thankful for links. Obviously, I have perused the MSDN Library. I have found a few good links on the web, but it seems that a lot of people are now using WPF and ObservableCollection.

My project is based on Winforms and .Net3.5 framework.

TIA

A: 

I'll answer both of your questions:

[I]f I changed my object to implement INotifyPropertyChanged, would the object collection (implementing BindingList) receive notifications of changes to the ScannedImage object?

If you actually use the BindingList<T> class inside System.ComponentModel, then it does contain special-case code for elements that impelment INotifyPropertyChanged. The list will see the property changes and will send out notifications.

However, you specifically ask about "implementing BindingList" which is subtly different. You can't implement a class. But there is an interface, IBindingList, that you can implement with your own class, and if this is the route you choose to take, then it becomes your responsibility when you write the list class to ensure that you monitor for property change notifications.

Generally you shouldn't need to create your own IBindingList implementation; just use BindingList<T> to wrap an existing list and you'll be fine.

Also, if Keywords were to implement INotifyPropertyChanged, would changes be accessible to the BindingList through the ScannedImage object?

No, they will not. BindingList<T> only looks at the specific object in the list, it has no ability to scan all dependencies and monitor everything in the graph (nor would that always be a good idea, if it were possible).

What you'll have to do if you want to receive notifications is update your ScannedImage class to check for property change notifications from the Keywords object, then fire its own PropertyChanged event in response.

Example:

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 { ... }

I hope you understand what's being done here. The owner, ScannedImage, automatically hooks the PropertyChanged event from its inner Keywords class and raises a separate property changed event saying that the Keywords have changed. This way, binding lists and other data binding controls will receive notification when the keywords change.

Aaronaught
Okay, one more question (I suppose that I will try, but I will ask for posterity...)Can my Keywords class have more than one PropertyChangedEventHandler?I ask because I would like to add and remove a single Keyword from it's list. Although the method you present would work - I would (usually) prefer to add a single Keyword to the list rather than treating it as "immutable."Actually, never-mind - I (think that I) just realized the answer. In KeywordsChanged, I should just test the sender and perform a switch on the type or the event arguments - correct?
EtherealMonkey
Also, yes - this makes much sense. I appreciate the example. The issue is a lot clearer now!
EtherealMonkey
@Ethereal: Sorry, I don't really understand what you're asking with that first question. I cannot think of any reason why you'd need to test the sender here. I think you're missing something but I'm not sure what; do you think that the `+= KeywordsChanged` line actually fires the event? It doesn't, it just wires up an event handler for when the properties *of* the `Keywords` change (as determined by that class's own implementation of the property change event). The entire structure is specifically designed for a *mutable* `Keywords` class that has its own `PropertyChanged ` event.
Aaronaught
@AaronaughtI apologize for any confusion.I simply see the SetKeywords() treating the Keywords class as being "immutable" because it is swapping out the entire object on each call.Now that I think about it, I will be treating the Keywords object as a List<Keyword>. So, nevermind... I know how to handle that ;-)
EtherealMonkey
Actually, this is current declaration for ImageKeywordList:public class ImageKeyWordList : IList<string>
EtherealMonkey
And, your answer still helps immensely. I have spent so much time looking for examples and documentation, that I overlooked something very simple. Having the ScannedImage class raise notification on behalf of the ImageKeyWordList.I think that I may have to subtype BindingList<T> because I will be caching a GUID for each BindingList, but I still get what I was missing. Thanks so much for your help.
EtherealMonkey