I'm aware that there are several posts about how to implement datagrid mutliselection.
I've found the open issue on Github (https://github.com/dotnet/wpf/issues/3140).
The user ice1e0 mentioned a solution with a CustomDataGrid
class.
public class CustomDataGrid : DataGrid
{
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(nameof(SelectedItems), typeof(IList), typeof(CustomDataGrid), new PropertyMetadata(default(IList), OnSelectedItemsPropertyChanged));
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
SetValue(SelectedItemsProperty, base.SelectedItems);
}
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'.");
}
private static void OnSelectedItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((CustomDataGrid)d).OnSelectedItemsChanged((IList)e.OldValue, (IList)e.NewValue);
}
protected virtual void OnSelectedItemsChanged(IList oldSelectedItems, IList newSelectedItems)
{
}
}
So, I tried to implement it, so I copied the class. And my xaml looks something like that:
<Project1:CustomDataGrid ItemsSource="{Binding Data}" SelectionMode="Extended" SelectionUnit="FullRow" IsReadOnly="True" SelectedItems="{Binding SelectedComputers, Mode=OneWayToSource}" />
and my ViewModel:
[ObservableProperty]
ObservableCollection<string> _selectedComputers;
I use CommunityToolkit.Mvvm (v8.0).
It compiles but SelectedComputers
is null, after I select one or multiple items.
UPDATE:
The issue seems that
void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.SelectedItemsList = this.SelectedItems;
}
doesn't work. SelectedItemsList
is always null. The problem is mentioned in the other thread: Select multiple items from a DataGrid in an MVVM WPF project
The suggested solution by M463:
this.SelectedItemsList = this.SelectedItems; did not work for me, as SelectedItemsList was always set to null. However, changing the code to foreach (var item in this.SelectedItems) { this.SelectedItemsList.Add(item); } did the trick. Please note, that this requires you to call this.SelectedItemsList.Clear(); in advance, so the items of SelectedItemsList will not get duplicated.
When I try the solution, after selected a row the application crashes with the error:
System.ArgumentException: 'The value "System.Data.DataRowView" is not of type "System.String" and cannot be used in this generic collection.
Parameter name: value'
CodePudding user response:
You cannot mix types.
If you Data
is a DataView
, SelectedItems
cannot be bound to an ObservableCollection<string>
because you cannot add a (selected) DataRowView
to an ObservableCollection<string>
.
Also, you cannot set an ObservableCollection<string>
property to anything else than an ObservableCollection<string>
. That's why the value in the setter of the source property comes in as null
when you try to set it to an IList
using SetValue
.
If you make SelectedComputers
an IList
, you should see it being set from the control:
[ObservableProperty]
IList _selectedComputers;
The other option is obviously to change the type of the dependency property.