1

I have designed a user control with an ObservableCollection dependency property and would like it to be consumed by a MVVM light application. If I set the property in the consuming view's code behind, it works like a charm, but not so when I attempt to use xaml binding as intended with a view-model.

In the control's code-behind I define the dependency property:

/// <summary>
/// The <see cref="ItemsSource" /> dependency property's name.
/// </summary>
public const string ItemsSourcePropertyName = "ItemsSource";

/// <summary>
/// Gets or sets the value of the <see cref="ItemsSource" />
/// property. This is a dependency property.
/// </summary>
public List<string> ItemsSource
{
    get
    {
        return (List<string>)GetValue(ItemsSourceProperty);
    }
    set
    {
        SetValue(ItemsSourceProperty, value);
    }
}

/// <summary>
/// Identifies the <see cref="ItemsSource" /> dependency property.
/// </summary>
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
    ItemsSourcePropertyName,
    typeof(List<string>),
    typeof(ListEditor), new PropertyMetadata(new List<string>(), OnItemsSourcePropertyChanged));

private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ListEditor listEditor = d as ListEditor;
    while (listEditor._stackPanel.Children.Count > 1)
    {
        listEditor._stackPanel.Children.RemoveRange(0, listEditor._stackPanel.Children.Count - 2);
    }

    List<string> newCollection = e.NewValue as List<string>;

    foreach (string item in newCollection)
    {
        ListItemEditor newItem = new ListItemEditor();
        newItem.Text = item;
        newItem.RemoveItem += listEditor.listItemEditor_RemoveItem;

        listEditor._stackPanel.Children.Insert(listEditor._stackPanel.Children.Count - 1, newItem);
    }
} 

In the view I bind the control:

<ucl:ListEditor ItemsSource="{Binding PartNumbers}"/>

In the view model I define the property:

/// <summary>
/// The <see cref="PartNumbers" /> property's name.
/// </summary>
public const string PartNumbersPropertyName = "PartNumbers";

private ObservableCollection<string> _partNumbers = new ObservableCollection<string>();

/// <summary>
/// Sets and gets the PartNumbers property.
/// Changes to that property's value raise the PropertyChanged event. 
/// </summary>
public ObservableCollection<string> PartNumbers
{
    get
    {
        return _partNumbers;
    }

    set
    {
        if (_partNumbers == value)
        {
            return;
        }

        RaisePropertyChanging(PartNumbersPropertyName);
        _partNumbers = value;
        RaisePropertyChanged(PartNumbersPropertyName);
    }
}

What can I do to facilitate the binding effectively?

Yael
  • 1,566
  • 3
  • 18
  • 25
  • Why are you defining `ItemsSourceProperty` as a dependency property? `ObservableCollection` itself implements `INotifyPropertyChanged`. – Arian Motamedi Mar 13 '14 at 18:31
  • Have you make sure that binding is not broken? Do you see any binding error in output window? Is getter of `PartNumbers` gets hit if you put breakpoint there? – Rohit Vats Mar 13 '14 at 18:31
  • @PoweredByOrange Good point. I changed it to a simple List see edit. – tomernation Mar 14 '14 at 13:05
  • @RohitVats Binding is not broken. If I bind it to as the ItemsSource of a ListView then its contents are correct. No binding errors in the output window. And yes, the getter of PartNumbers gets hit on breakpoint. – tomernation Mar 14 '14 at 13:07

0 Answers0