user568327
user568327

Reputation: 550

WPF DataGrid Multiselect with Virtualization enabled MVVM

I have a DataGrid with virtualization enabled and are trying to get multi-select to work.

I have defined DataGrid.ItemContainerStyle

        <DataGrid.ItemContainerStyle >
            <Style TargetType="{x:Type DataGridRow}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"></Setter>
            </Style>

Everything works fine if virtualization is disabled or if I don't scroll, but it stops working as soon as i scroll with virtualization enabled and DataGridRows goes out and in from memory. The IsSelected property stops setting IsSelected on my view models.

I have also tried to create a DependencyProperty to try to handle it my self. But random events are sent once I start to scroll with rows selected. A row I have not selected are for example sometimes called and the events are triggered multiple times.

I feel like this is something that should work by defualt. Do you know if multiselection should work and do you have any ideas of how I can resolve this?

Upvotes: 1

Views: 822

Answers (1)

user568327
user568327

Reputation: 550

I solved it by creating a dependency property

public static class DataGridSelectedItemsDependencyProperty
    {
        public static readonly DependencyProperty SelectedItemsChangedHandlerProperty =
            DependencyProperty.RegisterAttached("SelectedItemsChangedHandler",
                typeof(ICommand),
                typeof(DataGridSelectedItemsDependencyProperty),
                new FrameworkPropertyMetadata(OnSelectedItemsChangedHandlerChanged));


        public static ICommand GetSelectedItemsChangedHandler(DependencyObject element)
        {
            if (element == null)
                throw new ArgumentNullException(nameof(element));

            return element.GetValue(SelectedItemsChangedHandlerProperty) as ICommand;
        }

        public static void SetSelectedItemsChangedHandler(DependencyObject element, ICommand value)
        {
            if (element == null)
                throw new ArgumentNullException(nameof(element));

            element.SetValue(SelectedItemsChangedHandlerProperty, value);
        }

        private static void OnSelectedItemsChangedHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var dataGrid = (DataGrid)d;

            if (e.OldValue == null && e.NewValue != null)
                dataGrid.SelectionChanged += ItemsControl_SelectionChanged;

            if (e.OldValue != null && e.NewValue == null)
                dataGrid.SelectionChanged -= ItemsControl_SelectionChanged;
        }

        private static void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var dataGrid = (DataGrid)sender;
            var itemsChangedHandler = GetSelectedItemsChangedHandler(dataGrid);
            itemsChangedHandler.Execute(dataGrid.SelectedItems);
        }
    }

That I use like this in my view (xaml)

<DataGrid dependencyProperties:DataGridSelectedItemsDependencyProperty.SelectedItemsChangedHandler="{Binding SelectedItemsChanged}"

Upvotes: 1

Related Questions