I'm trying to create a twoway binding to the selected items in a WPF DataGrid. I want to be able to select multiple items from the ViewModel and also from the actual UserControl. I know I cannot directly set the selected items since this property is readonly.
I'm thinking of binding to a DependencyProperty and subscribing to the SelectionChanged event of the DataGrid in the code behind.
<UserControl.Resources>
<Style TargetType="local:ListView">
<Setter Property="SelectedItems" Value="{Binding SelectedItemsVM, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
<DataGrid Name="ObjectListDataGrid" SelectionChanged="OnSelectionChanged">
In the code behind I create the DependencyProperty. When this is set, I subscribe to the CollectionChanged event.
public ObservableCollection<object> SelectedItems
{
get { return (ObservableCollection<object>)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<object>), typeof(ListView), new PropertyMetadata(default(ObservableCollection<object>), OnSelectedItemsChanged));
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var collection = e.NewValue as ObservableCollection<object>;
if (collection != null)
{
collection.CollectionChanged -= OnSelectedItemsCollectionChanged;
collection.CollectionChanged += OnSelectedItemsCollectionChanged;
}
}
I use the EventHandler to the SelectionChanged event of the DataGrid to add/remove the items in the collection.
private void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
{
SelectedItems.Remove(args.RemovedItems);
SelectedItems.Add(args.AddedItems);
}
Now I want to select the rows needed in the OnSelectedItemsCollectionChanged method when the collection changes.
private static void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (DataGridRow row in ObjectListDataGrid.Rows())
{
if(ObjectListDataGrid.SelectedItems.Contains(row.Item))
row.IsSelected = true;
else
row.IsSelected = false;
}
}
The problem:
Since the OnSelectedItemsCollectionChanged method is static, I do not have access to the ObjectListDataGrid. Is there any way to overcome this, or do it in a different way?
For completeness, the DataGrid.Rows() method is an extension method to get a list of the rows:
public static IEnumerable<DataGridRow> Rows(this DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
asoperator (likee.NewValue as ObservableCollection<object>) only makes sense when the source object can legitimately be of any other (non-derived) type than the target type of the expression. - ClemensContains(row.Item). - Clemens