WPF .net 10 DelCommand implements ICommand, mvvm,

//MainWindow.xaml
<Window x:Class="WpfApp49.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:WpfApp49"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="{Binding MainTitle}" Height="450" Width="800">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding BooksCollection}"
                  IsReadOnly="True"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.VirtualizationMode="Recycling"
                  VirtualizingPanel.CacheLengthUnit="Item"
                  VirtualizingPanel.CacheLength="2,2"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False"
                  ScrollViewer.IsDeferredScrollingEnabled="True"
                  ScrollViewer.CanContentScroll="True">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding DataContext.GridWidth,RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                  Height="{Binding DataContext.GridHeight,RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
                                <Grid.Resources>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="FontSize" Value="30"/>
                                        <Style.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="FontSize" Value="50"/>
                                                <Setter Property="Foreground" Value="Red"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Grid.Resources>
                                <Grid.Background>
                                    <ImageBrush ImageSource="{Binding ImgSource}"
                                                Stretch="Uniform"/>
                                </Grid.Background>
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Id}"/>
                                <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"/>
                                <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding ISBN}"/>
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>                
            </DataGrid.Columns>
            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Export As Excel"
                              Command="{Binding ExportAsExcelCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource 
                              AncestorType={x:Type ContextMenu}},Path=PlacementTarget}"/>
                    <MenuItem Header="Export As CSV"
                              Command="{Binding ExportAsCSVCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource 
                              AncestorType={x:Type ContextMenu}},Path=PlacementTarget}"/>
                    <MenuItem Header="Export As PDF"
                              Command="{Binding ExportAsPDFCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource 
                              AncestorType={x:Type ContextMenu}},Path=PlacementTarget}"/>   
                </ContextMenu>
            </DataGrid.ContextMenu>
        </DataGrid>
    </Grid>
</Window>


//MainWindow.xaml.cs
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp49
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += async (s, e) =>
            {
                var vm = this.DataContext as MainVM;
                if(vm!=null)
                {
                    vm.GridWidth = this.ActualWidth - 50;
                    vm.GridHeight = this.ActualHeight - 50;
                    await vm.InitBooksCollectionAsync();
                }
            };
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private ConcurrentDictionary<string,ImageSource?> imgCache=new ConcurrentDictionary<string,ImageSource?>();
        public ICommand ExportAsExcelCommand { get; set; } = null!;
        public ICommand ExportAsCSVCommand { get; set; } = null!;
        public ICommand ExportAsPDFCommand { get; set; } = null!;
        public MainVM()
        {
            InitCommands();
        }

        private void InitCommands()
        {
            ExportAsExcelCommand = new DelCommand(ExportAsExcelCommandExecuted);
            ExportAsCSVCommand = new DelCommand(ExportAsCSVCommandExecuted);
            ExportAsPDFCommand = new DelCommand(ExportAsPDFCommandExecuted);
        }

        private void ExportAsExcelCommandExecuted(object? obj)
        {
            var dg = obj as DataGrid;
            if(dg!=null)
            {
                MessageBox.Show($"ExportAsExcelCommand");
            }
        }

        private void ExportAsCSVCommandExecuted(object? obj)
        {
            var dg = obj as DataGrid;
            if (dg != null)
            {
                MessageBox.Show($"ExportAsCSVCommand");
            }
        }

        private void ExportAsPDFCommandExecuted(object? obj)
        {
            var dg = obj as DataGrid;
            if (dg != null)
            {
                MessageBox.Show($"ExportAsPDFCommand");
            }
        }

        public async Task InitBooksCollectionAsync(int cnt=100000000)
        {
            BooksCollection = new ObservableCollection<Book>();
            var booksList = new List<Book>();
            var imgDir = @"../../../Images";
            if(!Directory.Exists(imgDir))
            {
                return;
            }
            var imgs=Directory.GetFiles(imgDir);
            int imgsCount = imgs.Count();
            for(int i=1;i<cnt+1;i++)
            {
                booksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    ImgSource = GetImageSource(imgs[i % imgsCount])
                });

                if(i%1000000==0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                }
            }

            if(booksList.Any())
            {
                await PopulateBooksCollectionAsync(booksList);
            }
        }

        private async Task PopulateBooksCollectionAsync(List<Book> booksList)
        {
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                var tempList = booksList.ToList();
                booksList.Clear();
                foreach (var bk in tempList)
                {
                    BooksCollection.Add(bk);
                }
                MainTitle = $"{DateTime.Now},loaded {BooksCollection.Count()} items,{GetMemory()}";
                tempList.Clear();
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        private string GetMemory()
        {
            var proc=Process.GetCurrentProcess();
            return $"memory {proc.PrivateMemorySize64 / 1024 / 1024:N2} M";
        }

        private ImageSource GetImageSource(string imgUrl)
        {
            if (!File.Exists(imgUrl))
            {
                return null;
            }

            if(imgCache.TryGetValue(imgUrl, out ImageSource? imageSource))
            {
                return imageSource;
            }

            BitmapImage bmi = new BitmapImage();
            bmi.BeginInit();
            bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute);
            bmi.CreateOptions = BitmapCreateOptions.DelayCreation;
            bmi.CacheOption = BitmapCacheOption.OnDemand;
            bmi.EndInit();

            imgCache.TryAdd(imgUrl, bmi);
            return bmi;
        }

        private string mainTitle;
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                if(value != mainTitle)
                {
                    mainTitle = value;
                    OnPropertyChanged();
                }
            }
        }

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

        private double gridHeight = 0.0;
        public double GridHeight
        {
            get
            {
                return gridHeight;
            }
            set
            {
                if (value != gridHeight)
                {
                    gridHeight = value;
                    OnPropertyChanged();
                }
            }
        }


        private double gridWidth = 0.0;
        public double GridWidth
        {
            get
            {
                return gridWidth;
            }
            set
            {
                if (value != gridWidth)
                {
                    gridWidth = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName="")
        {
            var handler = PropertyChanged;
            if(handler!=null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }
    }

    public class DelCommand : ICommand
    {
        private Action<object?>? execute;
        private Predicate<object?>? canExecute;
        public DelCommand(Action<object?>? executeValue, Predicate<object?>? canExecuteValue=null)
        {
            execute = executeValue??throw new ArgumentNullException(nameof(executeValue),"execute can't be null!");
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute?.Invoke(parameter);
        }
    }

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

 

 

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

 

 

image

 

posted @ 2026-01-09 22:39  FredGrit  阅读(5)  评论(0)    收藏  举报