Home > Software design >  Getting null in ViewModel from DependencyProperty after SetValue
Getting null in ViewModel from DependencyProperty after SetValue

Time:10-06

I have this extended ListBox with a SelectedItems property to be able to get the selected items from when SelectionMode is set to Extended.

public class BindableMultiSelectListBox : ListBox
{
    public static new readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(IList), typeof(BindableMultiSelectListBox),
            new PropertyMetadata(default(IList)));

    public new IList SelectedItems
    {
        get => (IList)GetValue(SelectedItemsProperty);
        set => throw new Exception("This property is read-only. To bind to it you must use 'Mode=OneWayToSource'.");
    }

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);
        SetValue(SelectedItemsProperty, base.SelectedItems);
    }
}

I use this in a view like this:

<usercontrols:BindableMultiSelectListBox SelectedItems="{Binding SelectedDogs, Mode=OneWayToSource}" ItemsSource="{Binding Dogs}" SelectionMode="Extended"/>

and bind to an ObservableCollection in my viewModel:

private ObservableCollection<string> _selectedDogs;

public ObservableCollection<string> SelectedDogs
{
    get
    {
        return _selectedDogs;
    }
    set
    {
        _selectedDogs = value;
        OnPropertyChanged(nameof(SelectedDogs));
    }
}

When I debug the OnSelectionChanged base.SelectedItems have the selected values as expected, but when the SelectedDogs setter is hit the value is null!

What have I done wrong here?

CodePudding user response:

The target property is supposed to bind to the source property.

Initialize the source collection in the view model:

public ObservableCollection<string> SelectedDogs { get; } = new ObservableCollection<string>();

...and implement the synchronization in the control:

protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
    base.OnSelectionChanged(e);
    if (SelectedItems != null)
    {
        foreach (var removed in e.RemovedItems)
            SelectedItems.Remove(removed);
        foreach (var added in e.AddedItems)
            SelectedItems.Add(added);
    }
}

XAML:

... SelectedItems="{Binding SelectedDogs}"

If you want to set the source property, you should initialize the collection in the control.

CodePudding user response:

Changing the SelectedDogs property in the viewModel from ObservableCollection<string> to just IList fixed the problem.

It seems to make little difference in practice, but what if I want to be able to specify ObservableCollection in my viewModel? Why doesn't ObservableCollection work? It does inherit from Collection which implements IList.

  • Related