WPF implement DelCommand inherited from ICommand from scratch

public class DelCommand : ICommand
{
    private Action<object?> execute;
    private Predicate<object?> canExecute;
    public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue =null)
    {
        execute = executeValue;
        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(parameter);
    }
}

 

 

 

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="{Binding MainTitle}">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <local:ImgUrlToImageSourceConverter x:Key="ImgUrlToImageSourceConverter"/>        
    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding BooksCollection}"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.VirtualizationMode="Recycling"
                  VirtualizingPanel.CacheLength="2,2"
                  VirtualizingPanel.CacheLengthUnit="Item"
                  ScrollViewer.CanContentScroll="True"
                  ScrollViewer.IsDeferredScrollingEnabled="True"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding DataContext.GridWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}"
                                  Height="{Binding DataContext.GridHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}">
                                <Grid.Resources>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="FontSize" Value="30"/>
                                        <Style.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Foreground" Value="Red"/>
                                                <Setter Property="FontSize" Value="100"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Grid.Resources>
                                <Grid.Background>
                                    <ImageBrush ImageSource="{Binding ImgUrl,Converter={StaticResource ImgUrlToImageSourceConverter}}"
                                                Stretch="Uniform"/>
                                </Grid.Background>
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <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="0" Grid.Column="2" Text="{Binding Topic}"/>
                                <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Text="{Binding ISBN}"/>
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>


using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
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.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            RenderOptions.ProcessRenderMode=System.Windows.Interop.RenderMode.Default;

            this.Loaded += async (s, e) =>
            {
                var vm = this.DataContext as MainVM;
                if(vm!=null)
                {
                    var fe = this.Content as FrameworkElement;
                    if(fe!=null)
                    {
                        vm.GridWidth= fe.ActualWidth;
                        vm.GridHeight= fe.ActualHeight;
                    }
                    await vm.InitBooksCollection(30500100);
                }
            };
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        public MainVM()
        {
           
        }

        public async Task InitBooksCollection(int cnt=10000000)
        {
            var img_dir = @"../../../Images";
            if (!Directory.Exists(img_dir))
            {
                return;
            }
            var imgs=Directory.GetFiles(img_dir);
            if(imgs==null ||!imgs.Any())
            {
                return;
            }
            int imgsCnt = imgs.Count();
            List<Book> booksList=new List<Book>();
            BooksCollection = new ObservableCollection<Book>();
            for (int i=0;i<cnt+1;i++)
            {
                booksList.Add(new Book()
                {
                    Id=i,
                    Name=$"Name_{i}",
                    ISBN=$"ISBN_{i}_{Guid.NewGuid():N}",
                    Topic=$"Topic_{i}",
                    ImgUrl = imgs[i%imgsCnt]
                });

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

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

        private async Task PopulateBooksCollectionAsync(List<Book> booksList, int i)
        {
            var tempList = booksList.ToList();
            booksList.Clear();            
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                foreach (var item in tempList)
                {
                    BooksCollection.Add(item);
                }

                MainTitle = $"{DateTime.Now},i:{i},{GetMem()}";
            },System.Windows.Threading.DispatcherPriority.Background);
        }

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

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

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

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

        public string GetMem()
        {
            var proc=Process.GetCurrentProcess();
            return $"Memory {proc.PrivateMemorySize64 / 1024 / 1024:.2f}M";
        }

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


    public class ImgUrlToImageSourceConverter : IValueConverter
    {
        Dictionary<string,ImageSource> imgDic=new Dictionary<string,ImageSource>();
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var imgUrl=value as string;
            if(!string.IsNullOrWhiteSpace(imgUrl) && File.Exists(imgUrl))
            {
                if(imgDic.ContainsKey(imgUrl))
                {
                    return imgDic[imgUrl];
                }
                BitmapImage bmi=new BitmapImage();
                bmi.BeginInit();
                bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute);
                bmi.CacheOption = BitmapCacheOption.OnDemand;
                bmi.EndInit();
                if(bmi.CanFreeze)
                {
                    bmi.Freeze();
                }
                imgDic[imgUrl] = bmi;
                return bmi;
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

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

    public class DelCommand : ICommand
    {
        private Action<object?> execute;
        private Predicate<object?> canExecute;
        public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue =null)
        {
            execute = executeValue;
            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(parameter);
        }
    }
}

 

image

 

 

 

 

image

 

 

 

image

 

 

 

image

 

posted @ 2026-02-25 23:25  FredGrit  阅读(14)  评论(0)    收藏  举报