当前位置: 首页 > news >正文

WPF Customize behavior and dependency property command

public class DataGridRightClickBehavior : Behavior<DataGrid>
{public ICommand SaveSelectedCommand{get { return (ICommand)GetValue(SaveSelectedCommandProperty); }set { SetValue(SaveSelectedCommandProperty, value); }}// Using a DependencyProperty as the backing store for SaveSelectedCommandProperty.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SaveSelectedCommandProperty =DependencyProperty.Register("SaveSelectedCommand", typeof(ICommand),typeof(DataGridRightClickBehavior), new PropertyMetadata(null));private ContextMenu contextMenu;protected override void OnAttached(){base.OnAttached();contextMenu = new ContextMenu();var menuItem = new MenuItem{Header = "Save Selected Items"};menuItem.Click += MenuItem_Click;contextMenu.Items.Add(menuItem);AssociatedObject.ContextMenu = contextMenu;}private void MenuItem_Click(object sender, RoutedEventArgs e){SaveSelectedCommand?.Execute(null);}protected override void OnDetaching(){base.OnDetaching();if (contextMenu != null){contextMenu.Items.Clear();contextMenu = null;}}
}

 

 

Install-Package Microsoft.Xaml.Behaviors.Wpf
Install-Package Newtonsoft.Json

 

 

<Window x:Class="WpfApp11.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:behavior="http://schemas.microsoft.com/xaml/behaviors"xmlns:local="clr-namespace:WpfApp11"mc:Ignorable="d"WindowState="Maximized"Title="{Binding MainTitle}"><Window.DataContext><local:MainVM/></Window.DataContext><Window.Resources><local:ImgConverter x:Key="ImgConverter"/></Window.Resources><Grid><DataGrid ItemsSource="{Binding BooksCollection}"SelectionMode="Extended"IsReadOnly="True"CanUserAddRows="True"AutoGenerateColumns="False"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLength="3,3"VirtualizingPanel.CacheLengthUnit="Item"ScrollViewer.CanContentScroll="True"ScrollViewer.IsDeferredScrollingEnabled="True"EnableRowVirtualization="True"EnableColumnVirtualization="True"UseLayoutRounding="True"SnapsToDevicePixels="True"><behavior:Interaction.Triggers><behavior:EventTrigger EventName="SelectionChanged"><behavior:InvokeCommandAction Command="{Binding SelectedBooksCommand}"CommandParameter="{Binding SelectedItems,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"></behavior:InvokeCommandAction></behavior:EventTrigger></behavior:Interaction.Triggers><behavior:Interaction.Behaviors><local:DataGridRightClickBehavior SaveSelectedCommand="{Binding SaveSelectedItemsCommand}"/></behavior:Interaction.Behaviors><DataGrid.Columns><DataGridTemplateColumn><DataGridTemplateColumn.CellTemplate><DataTemplate><Grid Width="{x:Static SystemParameters.FullPrimaryScreenWidth}" Height="{x:Static SystemParameters.FullPrimaryScreenHeight}"><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 ImgUrl,Converter={StaticResource ImgConverter}}"Stretch="Uniform"/></Grid.Background><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/><TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/><TextBlock Text="{Binding ISBN}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/></Grid></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns></DataGrid></Grid>
</Window>
using Microsoft.Xaml.Behaviors;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86;
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;
using System.Xml;
using Formatting = Newtonsoft.Json.Formatting;namespace WpfApp11
{/// <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){await vm.InitBooksCollection(5345678);}};}}public class MainVM : INotifyPropertyChanged{public MainVM(){//Task.Run(async () =>//{//    await InitBooksCollection(15000008);//});
            InitCommands();}private void InitCommands(){SelectedBooksCommand = new DelCommand(SelectedBooksCommandExecuted);SaveSelectedItemsCommand = new DelCommand(SaveSelectedItemsCommandExecuted);}private void SaveSelectedItemsCommandExecuted(object? obj){Task.Run(() =>{if (selectedBooksList.Any()){var jsonStr = JsonConvert.SerializeObject(selectedBooksList, Formatting.Indented);var jsonFile = $"Json_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";using (StreamWriter jsonWriter = new StreamWriter(jsonFile, false, Encoding.UTF8)){jsonWriter.WriteLine(jsonStr);System.Diagnostics.Debug.WriteLine($"{DateTime.Now}\nSaved {selectedBooksList.Count} items to {jsonFile}");}}});}private void SelectedBooksCommandExecuted(object? obj){Task.Run(() =>{selectedBooksList = ((System.Collections.IList)obj).Cast<Book>()?.ToList();System.Diagnostics.Debug.WriteLine($"{DateTime.Now},Selected {selectedBooksList.Count} items");});}private List<Book> selectedBooksList = new List<Book>();public ICommand SelectedBooksCommand { get; set; }public ICommand SaveSelectedItemsCommand { get; set; }public async Task InitBooksCollection(int cnt){var imgDir = @"../../../Images";if (!Directory.Exists(imgDir)){return;}var imgs = Directory.GetFiles(imgDir);if (imgs == null || !imgs.Any()){return;}int imgsCount = imgs.Count();BooksCollection = new ObservableCollection<Book>();List<Book> bksList = new List<Book>();for (int i = 1; i < cnt + 1; i++){bksList.Add(new Book(){Id = i,ImgUrl = imgs[i % imgsCount],ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",Name = $"Name_{i}"});if (i % 500000 == 0){await PopulateBooksCollectionAsync(bksList);}}if (bksList.Any()){await PopulateBooksCollectionAsync(bksList);}}private async Task PopulateBooksCollectionAsync(List<Book> bksList){var tempList = bksList.ToList();await Application.Current.Dispatcher.InvokeAsync(() =>{foreach (var bk in tempList){BooksCollection.Add(bk);}MainTitle = $"{DateTime.Now.ToString("O")},loaded {BooksCollection.Count} items,memory:{GetMem()}";bksList.Clear();}, System.Windows.Threading.DispatcherPriority.Background);}private string GetMem(){return $"{Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024:N2} M";}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();}}}public event PropertyChangedEventHandler? PropertyChanged;private void OnPropertyChanged([CallerMemberName] string propertyName = ""){var handler = PropertyChanged;handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}public class ImgConverter : IValueConverter{private readonly Dictionary<string, ImageSource> imgCache = new Dictionary<string, ImageSource>();private object lockObj = new object();public object Convert(object value, Type targetType, object parameter, CultureInfo culture){try{var imgUrl = value as string;if (string.IsNullOrEmpty(imgUrl) || !File.Exists(imgUrl)){return null;}lock (lockObj){if (imgCache.TryGetValue(imgUrl, out ImageSource img)){return img;}}using (var fs = new FileStream(imgUrl, FileMode.Open, FileAccess.Read, FileShare.Read)){var bmp = new BitmapImage();bmp.BeginInit();bmp.StreamSource = fs;bmp.CacheOption = BitmapCacheOption.OnLoad;bmp.EndInit();if(bmp.CanFreeze){bmp.Freeze();}lock(lockObj){if(!imgCache.ContainsKey(imgUrl)){imgCache.Add(imgUrl, bmp);}}return bmp;}}catch (Exception ex){System.Diagnostics.Debug.WriteLine($"{ex.Message}", $"{DateTime.Now.ToString("O")}");}return null;}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return DependencyProperty.UnsetValue;}}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?.Invoke(parameter);}}public class DataGridRightClickBehavior : Behavior<DataGrid>{public ICommand SaveSelectedCommand{get { return (ICommand)GetValue(SaveSelectedCommandProperty); }set { SetValue(SaveSelectedCommandProperty, value); }}// Using a DependencyProperty as the backing store for SaveSelectedCommandProperty.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SaveSelectedCommandProperty =DependencyProperty.Register("SaveSelectedCommand", typeof(ICommand),typeof(DataGridRightClickBehavior), new PropertyMetadata(null));private ContextMenu contextMenu;protected override void OnAttached(){base.OnAttached();contextMenu = new ContextMenu();var menuItem = new MenuItem{Header = "Save Selected Items"};menuItem.Click += MenuItem_Click;contextMenu.Items.Add(menuItem);AssociatedObject.ContextMenu = contextMenu;}private void MenuItem_Click(object sender, RoutedEventArgs e){SaveSelectedCommand?.Execute(null);}protected override void OnDetaching(){base.OnDetaching();if (contextMenu != null){contextMenu.Items.Clear();contextMenu = null;}}}public class Book{public int Id { get; set; }public string Name { get; set; }public string ISBN { get; set; }public string ImgUrl { get; set; }}
}

 

 

 

 

 

image

 

image

 

image

 

 

image

 

http://www.jsqmd.com/news/593598/

相关文章:

  • 2026年喷淋塔除尘器制造商推荐分析,静电除尘器/活性炭吸附/干式打磨台/水帘除尘器,喷淋塔除尘器订制厂家哪家好 - 品牌推荐师
  • ScanNet数据集深度解析:如何利用segs.json和aggregation.json实现点云语义分割
  • AGX Orin 部署PyTorch生态:从JetPack适配到torchvision编译避坑指南
  • VASP机器学习力场训练避坑指南:从500步MD失败到高质量声子谱验证
  • 2025届学术党必备的五大降AI率工具横评
  • 零代码玩转扣子(Coze)智能体:3步生成专属视频教程
  • CF1762D GCD Queries - Rye
  • 【网络安全实战入门】从零到一:在VMware上部署Kali Linux 2022全流程解析
  • 计算机毕业设计:Python地铁运营全维度数据可视化与后台管理系统 Django框架 数据分析 可视化 大数据 机器学习 深度学习(建议收藏)✅
  • OpenClaw、Agent、Skill、MCP 深度解读与区分分析
  • 第三期漫画周报
  • 实验二 C语言分支与循环基础应用编程
  • 2026年花洒产品推荐:花洒哪个品牌好?4款热门花洒排行榜
  • Linux下WRF-Chem Intel编译器实战:从环境配置到编译成功的避坑指南
  • 高效使用Ultimaker Cura:从入门到精通的3D打印切片工作流
  • 非华为电脑也能用上鸿蒙生态?手把手教你给Win10/Win11装上最新华为电脑管家(附移动应用引擎开启方法)
  • 告别printk:用Linux内核Tracepoint给你的驱动调试换个活法(附ext4实战代码)
  • AI元人文:自感痕迹论——工夫与功夫的再辩证
  • 04 月 05 日 AI 每日参考:谷歌 Gemma 4 开源 国产 AI 算力生态强势崛起
  • EC11编码器硬件设计避坑指南:上拉电阻选择与PCB布局要点
  • 基于Quartus平台的RISCV五级流水线CPU设计与验证
  • Gym - 100624D Non-boring sequences
  • MDIN380芯片高清视频处理方案:SDI转VGA与LVDS转换,专业PCB设计与源码集成
  • olonCode v0.0.20 发布 - 编程智能体(新增子代理和浏览器能力)
  • [T.2] 团队项目:选题和需求分析
  • Scratch二次开发实战:如何按需“阉割”菜单栏功能?从关闭语言切换、主题到隐藏教程按钮
  • 当openclaw安装报错时:如何用快马ai模型快速诊断与生成修复方案
  • 可伴臻选购物卡回收方式 - 京顺回收
  • AI时代程序员必看!揭秘Harness Engineerin
  • 对接亚马逊 SP-API(Amazon Selling Partner API) 第一章:AWS IAM 配置详解