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
.