WPF datagrid mvvm multi select via customize datagrid

FredGrit發表於2024-04-07
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp39
{
    public class MultiSelectDataGrid:DataGrid
    {
        public static readonly DependencyProperty SelectedItemsProperty =
       DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectDataGrid), new PropertyMetadata(default(IList)));

        public new IList SelectedItems
        {
            get { return (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);
        }
    }
}
<Window x:Class="WpfApp39.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp39"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d" WindowState="Maximized"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="FontSize" Value="30"/>
                    <Setter Property="FontWeight" Value="ExtraBold"/>
                    <Setter Property="Foreground" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <local:MultiSelectDataGrid x:Name="dg" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                  SelectionMode="Extended" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                  BorderBrush="Blue" BorderThickness="5" SelectedItems="{Binding SelectedBooks,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" >
        </local:MultiSelectDataGrid>
    </Grid>
</Window>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace WpfApp39
{
    public class MainVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }

        public MainVM()
        {
            InitItemsSource(); 
        }

        private void InitItemsSource()
        {
            BooksCollection = new ObservableCollection<Book>();
            for(int i=0;i<10000;i++)
            {
                BooksCollection.Add(new Book()
                {
                    Id=i+1,
                    Title=$"Title__{Guid.NewGuid()}",
                    ISBN=$"ISBN__{Guid.NewGuid()}",
                    Name=$"Name_{Guid.NewGuid()}"
                });
            }
        }

        private ObservableCollection<Book> booksCollection;

        public ObservableCollection<Book> BooksCollection
        {
            get
            {
                return booksCollection;
            }
            set
            {
                if (value != booksCollection)
                {
                    booksCollection = value;
                    OnPropertyChanged("BooksCollection");
                }
            }
        }

        private ObservableCollection<Book> selectedBooksCollection;
        public ObservableCollection<Book> SelectedBooksCollection
        {
            get
            {
                return selectedBooksCollection;
            }
            set
            {
                if(value != selectedBooksCollection)
                { 
                    selectedBooksCollection = value;
                    OnPropertyChanged("SelectedBooksCollection");
                }
            }
        }

        private IList selectedBooks;
        public IList SelectedBooks
        {
            get
            {
                return selectedBooks;
            }
            set
            {
                selectedBooks = value;
                if(selectedBooks!=null && selectedBooks.Count>0)
                {
                    MessageBox.Show($"Selected {selectedBooks?.Count} items", "Multi Selected", MessageBoxButton.OK, MessageBoxImage.Information);
                } 
            }
        }

        private DelegateCmd selectedMultiCommand;
        public DelegateCmd SelectedMultiCommand
        {
            get
            {
                if (selectedMultiCommand == null)
                {
                    selectedMultiCommand = new DelegateCmd(SelectedMultiCommandExecuted);
                }
                return selectedMultiCommand;
            }
        }

        private void SelectedMultiCommandExecuted(object obj)
        {
            System.Collections.IList tempIList = obj as System.Collections.IList;
            if (tempIList != null && tempIList.Count > 0)
            {
                SelectedBooksCollection = new ObservableCollection<Book>();
                foreach (var item in tempIList) 
                {
                    Book tempBk = item as Book;
                    if(tempBk != null) 
                    {
                        SelectedBooksCollection.Add(tempBk);
                    }
                }
            }

            //StringBuilder builder = new StringBuilder();
            //foreach (var item in SelectedBooksCollection)
            //{
            //    builder.AppendLine($"{item.Id},{item.Name}");
            //}
            //System.Windows.MessageBox.Show($"Selected {SelectedBooksCollection.Count} items","Information",MessageBoxButton.OK,MessageBoxImage.Information);
        }
    }

    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string Title { get; set; }

    }

    public class DelegateCmd : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;
        public DelegateCmd(Action<object> executeValue, Predicate<object> canExecuteValue)
        {
            _execute = executeValue;
            _canExecute = canExecuteValue;
        }

        public DelegateCmd(Action<object> executeValue) : this(executeValue, null)
        {
        }

        public event EventHandler CanExecuteChanged;
        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }
            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

}

The key contains two parts

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp39
{
    public class MultiSelectDataGrid:DataGrid
    {
        public static readonly DependencyProperty SelectedItemsProperty =
       DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectDataGrid), new PropertyMetadata(default(IList)));

        public new IList SelectedItems
        {
            get { return (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);
        }
    }
}


 <Grid>
     <local:MultiSelectDataGrid x:Name="dg" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
               SelectionMode="Extended" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
               BorderBrush="Blue" BorderThickness="5" SelectedItems="{Binding SelectedBooks,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" >
     </local:MultiSelectDataGrid>
 </Grid>




 private IList selectedBooks;
 public IList SelectedBooks
 {
     get
     {
         return selectedBooks;
     }
     set
     {
         selectedBooks = value;
         if(selectedBooks!=null && selectedBooks.Count>0)
         {
             MessageBox.Show($"Selected {selectedBooks?.Count} items", "Multi Selected", MessageBoxButton.OK, MessageBoxImage.Information);
         } 
     }
 }

referenced https://stackoverflow.com/questions/9880589/bind-to-selecteditems-from-datagrid-or-listbox-in-mvvm#

相關文章