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

WPF DataGrid customize behavior with multiple commands and command parameters then invoke in mvvm

Install-Package Microsoft.Xaml.Behaviors.WPF

 

 

 public class ListBoxBehavior : Behavior<ListBox>{private ContextMenu ctxMenu;private MenuItem saveItem;private MenuItem selectItem;public ListBoxBehavior(){}public ICommand SaveCommand{get { return (ICommand)GetValue(SaveCommandProperty); }set { SetValue(SaveCommandProperty, value); }}// Using a DependencyProperty as the backing store for SaveCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SaveCommandProperty =DependencyProperty.Register(nameof(SaveCommand), typeof(ICommand), typeof(ListBoxBehavior),new PropertyMetadata(null));public object CmdPara{get { return (object)GetValue(CmdParaProperty); }set { SetValue(CmdParaProperty, value); }}// Using a DependencyProperty as the backing store for CmdPara.  This enables animation, styling, binding, etc...public static readonly DependencyProperty CmdParaProperty =DependencyProperty.Register(nameof(CmdPara), typeof(object),typeof(ListBoxBehavior), new PropertyMetadata(""));public ICommand SelectCommand{get { return (ICommand)GetValue(SelectCommandProperty); }set { SetValue(SelectCommandProperty, value); }}// Using a DependencyProperty as the backing store for SelectCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectCommandProperty =DependencyProperty.Register(nameof(SelectCommand), typeof(ICommand), typeof(ListBoxBehavior),new PropertyMetadata(null));public object SelectCmdPara{get { return (object)GetValue(SelectCmdParaProperty); }set { SetValue(SelectCmdParaProperty, value); }}// Using a DependencyProperty as the backing store for SelectCmdPara.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectCmdParaProperty =DependencyProperty.Register(nameof(SelectCmdPara), typeof(object), typeof(ListBoxBehavior),new PropertyMetadata(null));protected override void OnAttached(){CreateContextMenu();base.OnAttached();}private void CreateContextMenu(){ctxMenu = new ContextMenu();saveItem = new MenuItem();saveItem.Width = 200;saveItem.Height = 50;saveItem.Header = "Save";saveItem.FontSize = 30;saveItem.Click += SaveItem_Click;ctxMenu.Items.Add(saveItem);selectItem = new MenuItem(){Width = 200,Height = 50,Header = "Select",FontSize = 30};selectItem.Click += SelectItem_Click;ctxMenu.Items.Add(selectItem);AssociatedObject.ContextMenu = ctxMenu;}private void SelectItem_Click(object sender, RoutedEventArgs e){SelectCommand?.Execute(SelectCmdPara);}private void SaveItem_Click(object sender, RoutedEventArgs e){SaveCommand?.Execute(CmdPara);}protected override void OnDetaching(){base.OnDetaching();if (saveItem != null){saveItem.Click -= SaveItem_Click;saveItem = null;}if (ctxMenu != null){ctxMenu.Items.Clear();ctxMenu = null;}AssociatedObject.ContextMenu = null;}}<behavior:Interaction.Behaviors><local:ListBoxBehavior SaveCommand="{Binding DataContext.SaveCmd,RelativeSource={RelativeSource AncestorType=Window}}"CmdPara="{Binding Path=ItemsSource,RelativeSource={RelativeSource AncestorType=ListBox}}"SelectCommand="{Binding DataContext.SelectCmd,RelativeSource={RelativeSource AncestorType=Window}}" SelectCmdPara="{Binding Path=SelectedItem,RelativeSource={RelativeSource AncestorType=ListBox}}"/></behavior:Interaction.Behaviors>public ICommand SaveCmd { get; set; }
public ICommand SelectCmd { get; set; }SaveCmd = new DelCommand(SaveCmdExecuted);SelectCmd = new DelCommand(SelectCmdExecuted);private void SelectCmdExecuted(object? obj){var bk = obj as Book;if (bk != null){MessageBox.Show($"{bk.ToString()}", $"{DateTime.Now}");}}private void SaveCmdExecuted(object? obj){var items = ((System.Collections.IList)obj).Cast<Book>()?.ToList();if (items != null && items.Any()){MessageBox.Show($"{items.Count} items", $"{DateTime.Now}");}}

 

 

<Window x:Class="WpfApp22.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:WpfApp22"xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors"mc:Ignorable="d"WindowState="Maximized"Title="{Binding MainTitle}"><Window.DataContext><local:MainVM/></Window.DataContext><Grid><ListBox ItemsSource="{Binding BooksCollection}"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLengthUnit="Item"VirtualizingPanel.CacheLength="2,2"UseLayoutRounding="True"SnapsToDevicePixels="True"ScrollViewer.CanContentScroll="True"ScrollViewer.IsDeferredScrollingEnabled="True"><ListBox.Resources><Style TargetType="ListBoxItem"><Setter Property="FontSize" Value="20"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="FontSize" Value="30"/><Setter Property="Foreground" Value="Red"/></Trigger></Style.Triggers></Style></ListBox.Resources><behavior:Interaction.Behaviors><local:ListBoxBehavior SaveCommand="{Binding DataContext.SaveCmd,RelativeSource={RelativeSource AncestorType=Window}}"CmdPara="{Binding Path=ItemsSource,RelativeSource={RelativeSource AncestorType=ListBox}}"SelectCommand="{Binding DataContext.SelectCmd,RelativeSource={RelativeSource AncestorType=Window}}" SelectCmdPara="{Binding Path=SelectedItem,RelativeSource={RelativeSource AncestorType=ListBox}}"/></behavior:Interaction.Behaviors></ListBox></Grid>
</Window>using Microsoft.Xaml.Behaviors;
using System.Collections.ObjectModel;
using System.ComponentModel;
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 WpfApp22
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}}public class MainVM : INotifyPropertyChanged{public ICommand SaveCmd { get; set; }public ICommand SelectCmd { get; set; }public MainVM(){SaveCmd = new DelCommand(SaveCmdExecuted);SelectCmd = new DelCommand(SelectCmdExecuted);Task.Run(async () =>{await InitBooksCollectionAsync();});}private void SelectCmdExecuted(object? obj){var bk = obj as Book;if (bk != null){MessageBox.Show($"{bk.ToString()}", $"{DateTime.Now}");}}private void SaveCmdExecuted(object? obj){var items = ((System.Collections.IList)obj).Cast<Book>()?.ToList();if (items != null && items.Any()){MessageBox.Show($"{items.Count} items", $"{DateTime.Now}");}}private async Task InitBooksCollectionAsync(int cnt = 50000000){BooksCollection = new ObservableCollection<Book>();List<Book> bksList = new List<Book>();for (int i = 1; i < cnt + 1; i++){bksList.Add(new Book(){Id = i,Name = $"Name_{i}",ISBN = $"ISBN_{i}_{Guid.NewGuid():N}"});if (i % 1000000 == 0){await Application.Current.Dispatcher.InvokeAsync(() =>{var tempList = bksList.ToList();bksList.Clear();foreach (var bk in tempList){BooksCollection.Add(bk);}MainTitle = $"{DateTime.Now},loaded {BooksCollection.Count} items,{GetMem()}";}, System.Windows.Threading.DispatcherPriority.Background);}}}private string GetMem(){return $"memory {System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024:N2} M";}private string mainTitle = $"{DateTime.Now},loading...";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 (booksCollection != value){booksCollection = value;OnPropertyChanged();}}}public event PropertyChangedEventHandler? PropertyChanged;private void OnPropertyChanged([CallerMemberName] string propName = ""){var handler = PropertyChanged;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;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 ListBoxBehavior : Behavior<ListBox>{private ContextMenu ctxMenu;private MenuItem saveItem;private MenuItem selectItem;public ListBoxBehavior(){}public ICommand SaveCommand{get { return (ICommand)GetValue(SaveCommandProperty); }set { SetValue(SaveCommandProperty, value); }}// Using a DependencyProperty as the backing store for SaveCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SaveCommandProperty =DependencyProperty.Register(nameof(SaveCommand), typeof(ICommand), typeof(ListBoxBehavior),new PropertyMetadata(null));public object CmdPara{get { return (object)GetValue(CmdParaProperty); }set { SetValue(CmdParaProperty, value); }}// Using a DependencyProperty as the backing store for CmdPara.  This enables animation, styling, binding, etc...public static readonly DependencyProperty CmdParaProperty =DependencyProperty.Register(nameof(CmdPara), typeof(object),typeof(ListBoxBehavior), new PropertyMetadata(""));public ICommand SelectCommand{get { return (ICommand)GetValue(SelectCommandProperty); }set { SetValue(SelectCommandProperty, value); }}// Using a DependencyProperty as the backing store for SelectCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectCommandProperty =DependencyProperty.Register(nameof(SelectCommand), typeof(ICommand), typeof(ListBoxBehavior),new PropertyMetadata(null));public object SelectCmdPara{get { return (object)GetValue(SelectCmdParaProperty); }set { SetValue(SelectCmdParaProperty, value); }}// Using a DependencyProperty as the backing store for SelectCmdPara.  This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectCmdParaProperty =DependencyProperty.Register(nameof(SelectCmdPara), typeof(object), typeof(ListBoxBehavior),new PropertyMetadata(null));protected override void OnAttached(){CreateContextMenu();base.OnAttached();}private void CreateContextMenu(){ctxMenu = new ContextMenu();saveItem = new MenuItem();saveItem.Width = 200;saveItem.Height = 50;saveItem.Header = "Save";saveItem.FontSize = 30;saveItem.Click += SaveItem_Click;ctxMenu.Items.Add(saveItem);selectItem = new MenuItem(){Width = 200,Height = 50,Header = "Select",FontSize = 30};selectItem.Click += SelectItem_Click;ctxMenu.Items.Add(selectItem);AssociatedObject.ContextMenu = ctxMenu;}private void SelectItem_Click(object sender, RoutedEventArgs e){SelectCommand?.Execute(SelectCmdPara);}private void SaveItem_Click(object sender, RoutedEventArgs e){SaveCommand?.Execute(CmdPara);}protected override void OnDetaching(){base.OnDetaching();if (saveItem != null){saveItem.Click -= SaveItem_Click;saveItem = null;}if (ctxMenu != null){ctxMenu.Items.Clear();ctxMenu = null;}AssociatedObject.ContextMenu = null;}}public class Book{public int Id { get; set; }public string Name { get; set; }public string ISBN { get; set; }public override string ToString(){return $"Id:{Id},Name:{Name},ISBN:{ISBN}";}}
}

 

 

 

 

 

image

 

 

 

image

 

 

 

 

 

 

image

 

 

 

image

 

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

相关文章:

  • 3个关键步骤实现稳定黑苹果系统:从硬件兼容到完美驱动
  • Windows 10/11 下 R 4.2.2 与 JAGS 4.3.1 版本匹配避坑实录:手把手搞定 infercnv 环境搭建
  • Creality Print:如何用开源切片软件打造完美3D打印作品?
  • 别再只盯着电压电流了!手把手教你读懂USB PD 3.2扩展消息里的‘身份证’与‘体检报告’
  • MCP 2026车载适配实战指南:从ECU通信协议对接到ASAM AML模型验证的5大关键动作
  • 如何彻底摆脱Dell G15官方散热软件的束缚:开源替代方案完全指南
  • 老旧安卓电视的终极救星:MyTV-Android免费直播完整指南
  • Docker Sandbox运行AI代码:为什么92%的AI工程团队仍在用危险的--privileged模式?
  • [具身智能-459]:数据标注的演进是一部从“劳动密集型”向“技术密集型”深刻转型的历史:手工作坊时代->流程化、工业化时代->生成人机协同时代->全自动与合成数据阶段
  • AI模型容器化部署风险暴雷预警,2026新版自动合规审计模块已强制启用,你的CI/CD流水线还安全吗?
  • SocialEcho vs Sprout Social vs Buffer:2026 年社媒管理工具终极对比 - SocialEcho社媒管理
  • [具身智能-460]:openCV在自动数据标注中的应用
  • LinkSwift:八大网盘平台直链获取解决方案的技术解析与应用指南
  • 桌面后端开发本地服务与系统集成
  • 在F1C100s上跑GBA游戏:手把手教你用Buildroot配置SDL和移植gpsp模拟器
  • Docker AI Toolkit 2026核心能力解密(内测工程师亲授的7个隐藏API与自动合规审计开关)
  • VS Code MCP插件对比评测报告(2024Q3实测数据版):12款主流MCP服务器响应延迟、协议兼容性、调试稳定性三维打分揭榜
  • VS Code Copilot Next 自动化配置到底难在哪?揭秘微软内部培训文档中的3类高频报错与秒级修复法
  • Mybatis入门手册
  • Synology HDD db:3步解锁群晖NAS硬盘兼容性限制的终极指南
  • Godot游戏资源解包终极指南:快速提取PCK文件的完整解决方案
  • 微信立减金怎么兑换?闲置额度居然能变实打实的零花钱 - 京顺回收
  • 3分钟上手Translumo:打破语言障碍的智能屏幕翻译神器
  • 抖音无水印视频下载终极指南:3分钟掌握批量下载技巧,轻松获取高清资源
  • FreeModbus移植避坑指南:如何优雅地处理临界区与事件队列(含FreeRTOS示例)
  • 魔兽世界API与宏命令工具:提升游戏体验的终极解决方案
  • AI时代的To B PMF,还成立吗?
  • 像搭积木一样改造你的Windows系统
  • 小红书数据采集技术解决方案:基于Appium与Mitmproxy的混合架构实现
  • 【优化求解】带惯性项的自适应交替方向乘子法iADMMn求解带正则化的逻辑回归矩阵分解问题(对比ADMM和梯度下降法GD算法)【含Matlab源码 15370期】