Friday, May 6, 2011

WPF: Adding an element to a databound Collection (a Dependency Property)

I have this DependencyProperty which holds an entity with a property that is a collection (ShoutBox.Entities):

public static readonly DependencyProperty ShoutBoxProperty = DependencyProperty.Register("ShoutBox",typeof (ShoutBox),typeof (ShoutBoxViewerControl));

public ShoutBox ShoutBox
{
    get { return (ShoutBox) GetValue(ShoutBoxProperty); }
    set { SetValue(ShoutBoxProperty, value); }
}

It is being binded in xaml like such:

<ItemsControl ItemsSource="{Binding ShoutBox.Entries}">
.
.
</ItemsControl>

When I bind it the first time, it works as expected but there are times when I need to add items to the collection (with a method that is in the same control), like such:

public void AddNewEntry(ShoutBoxEntry newEntry)
{
    Dispatcher.Invoke(new Action(() =>{
        ShoutBox.Entries.Add(newEntry); //Adding directly the the Dependency property
    }));
}

The problem is that when I add a new element with the above method, the item isn't being displayed in the ItemsControl.


My question is, why isn't the new element that I am adding isn't being displayed in the ItemsControl ?


[Edit]

Entries (ShoutBox.Entries) is of type List<ShoutBoxEntry>

From stackoverflow
  • What is the type of Entries? It either needs to be ObservableCollection or implement ICollectionChanged. Otherwise the binding doesn't know that a new item has been added.

    Andreas Grech : List
    NotDan : That's the problem. Change the List to an ObservableCollection, and it should work. http://msdn.microsoft.com/en-us/library/ms668604.aspx
    Bryan Anderson : In order to pick up adding and removing items the Collection needs to implement ICollectionChanged, not INotifyPropertyChanged.
    NotDan : This is Fixed now.
  • Changing the type of Entries should indeed solve the problem... If you want to avoid the explicit call to Dispatcher.Invoke, I wrote a collection that raises the CollectionChanged and PropertyChanged events on the thread that created the collection :

    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
    
        public AsyncObservableCollection()
        {
        }
    
        public AsyncObservableCollection(IEnumerable<T> list)
            : base(list)
        {
        }
    
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the CollectionChanged event on the current thread
                RaiseCollectionChanged(e);
            }
            else
            {
                // Post the CollectionChanged event on the creator thread
                _synchronizationContext.Post(RaiseCollectionChanged, e);
            }
        }
    
        private void RaiseCollectionChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
        }
    
        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (SynchronizationContext.Current == _synchronizationContext)
            {
                // Execute the PropertyChanged event on the current thread
                RaisePropertyChanged(e);
            }
            else
            {
                // Post the PropertyChanged event on the creator thread
                _synchronizationContext.Post(RaisePropertyChanged, e);
            }
        }
    
        private void RaisePropertyChanged(object param)
        {
            // We are in the creator thread, call the base implementation directly
            base.OnPropertyChanged((PropertyChangedEventArgs)param);
        }
    }
    

    More details can be found here : http://tomlev2.wordpress.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/

0 comments:

Post a Comment