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

WPF customize behavior based on Microsoft.Xaml.Behaviors.Wpf with command and commandparameter

Install-Package Microsoft.Xaml.Behaviors.WPF

 

public class GridBehavior : Behavior<Grid>
{private ContextMenu contextMenu;public GridBehavior(){contextMenu = new ContextMenu();MenuItem mi = new MenuItem();mi.Header = "Save";mi.Click += Mi_Click;contextMenu.Items.Add(mi);}private void Mi_Click(object sender, RoutedEventArgs e){RightButtonSaveCommand?.Execute(CmdPara);}protected override void OnAttached(){base.OnAttached();AssociatedObject.ContextMenu = contextMenu;}protected override void OnDetaching(){base.OnDetaching();AssociatedObject.ContextMenu = null;}public ICommand RightButtonSaveCommand{get { return (ICommand)GetValue(RightButtonSaveCommandProperty); }set { SetValue(RightButtonSaveCommandProperty, value); }}// Using a DependencyProperty as the backing store for RightButtonSaveCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty RightButtonSaveCommandProperty =DependencyProperty.Register(nameof(RightButtonSaveCommand), typeof(ICommand),typeof(GridBehavior), 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(GridBehavior), new PropertyMetadata(null));}<ItemsControl ItemsSource="{Binding BooksCollection}"><ItemsControl.Template><ControlTemplate><ScrollViewer CanContentScroll="True"><VirtualizingStackPanel IsItemsHost="True"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLength="3,3"VirtualizingPanel.CacheLengthUnit="Item"UseLayoutRounding="True"SnapsToDevicePixels="True"ScrollViewer.IsDeferredScrollingEnabled="True"ScrollViewer.CanContentScroll="True"/></ScrollViewer></ControlTemplate></ItemsControl.Template><ItemsControl.ItemTemplate><DataTemplate><Grid Width="{x:Static SystemParameters.FullPrimaryScreenWidth}"Height="{x:Static SystemParameters.FullPrimaryScreenHeight}"><Grid.Resources><Style TargetType="TextBlock"><Setter Property="FontSize" Value="50"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="FontSize" Value="100"/><Setter Property="Foreground" Value="Red"/></Trigger></Style.Triggers></Style></Grid.Resources><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Image Source="{Binding ImgUrl,Converter={StaticResource ImgUrlConverter}}"Stretch="Fill"Grid.Row="0"Grid.RowSpan="2"Grid.Column="0"Grid.ColumnSpan="2"/><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"/><behavior:Interaction.Behaviors><local:GridBehavior RightButtonSaveCommand="{Binding DataContext.SaveCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
                                        CmdPara="{Binding}" /></behavior:Interaction.Behaviors><!--<behavior:Interaction.Triggers><behavior:EventTrigger EventName="MouseUp"><behavior:InvokeCommandAction Command="{Binding DataContext.SaveCommand2,RelativeSource={RelativeSource AncestorType=Window}}"/></behavior:EventTrigger></behavior:Interaction.Triggers>--></Grid></DataTemplate></ItemsControl.ItemTemplate>
</ItemsControl>SaveCommand = new DelCommand(SaveCommandExecuted);
private void SaveCommandExecuted(object? obj)
{var bk = obj as Book;if (bk != null){System.Diagnostics.Debug.WriteLine(bk.ToString());}
}

image

 

 

<Window x:Class="WpfApp16.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:WpfApp16"mc:Ignorable="d"WindowState="Maximized"        Title="{Binding MainTitle}"><Window.DataContext><local:MainVM/></Window.DataContext><Window.Resources><local:ImgUrlConverter x:Key="ImgUrlConverter"/></Window.Resources><Grid><ItemsControl ItemsSource="{Binding BooksCollection}"><ItemsControl.Template><ControlTemplate><ScrollViewer CanContentScroll="True"><VirtualizingStackPanel IsItemsHost="True"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLength="3,3"VirtualizingPanel.CacheLengthUnit="Item"UseLayoutRounding="True"SnapsToDevicePixels="True"ScrollViewer.IsDeferredScrollingEnabled="True"ScrollViewer.CanContentScroll="True"/></ScrollViewer></ControlTemplate></ItemsControl.Template><ItemsControl.ItemTemplate><DataTemplate><Grid Width="{x:Static SystemParameters.FullPrimaryScreenWidth}"Height="{x:Static SystemParameters.FullPrimaryScreenHeight}"><Grid.Resources><Style TargetType="TextBlock"><Setter Property="FontSize" Value="50"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="FontSize" Value="100"/><Setter Property="Foreground" Value="Red"/></Trigger></Style.Triggers></Style></Grid.Resources><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Image Source="{Binding ImgUrl,Converter={StaticResource ImgUrlConverter}}"Stretch="Fill"Grid.Row="0"Grid.RowSpan="2"Grid.Column="0"Grid.ColumnSpan="2"/><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"/><behavior:Interaction.Behaviors><local:GridBehavior RightButtonSaveCommand="{Binding DataContext.SaveCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
                                                CmdPara="{Binding}" /></behavior:Interaction.Behaviors><!--<behavior:Interaction.Triggers><behavior:EventTrigger EventName="MouseUp"><behavior:InvokeCommandAction Command="{Binding DataContext.SaveCommand2,RelativeSource={RelativeSource AncestorType=Window}}"/></behavior:EventTrigger></behavior:Interaction.Triggers>--></Grid></DataTemplate></ItemsControl.ItemTemplate></ItemsControl></Grid>
</Window>using Microsoft.Xaml.Behaviors;
using System.Collections.ObjectModel;
using System.ComponentModel;
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 WpfApp16
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}}public class MainVM : INotifyPropertyChanged{public ICommand SaveCommand { get; set; }public ICommand SaveCommand2 { get; set; }public MainVM(){Task.Run(async () =>{await InitBooksCollectionAsync();});SaveCommand = new DelCommand(SaveCommandExecuted);SaveCommand2 = new DelCommand(SaveCommand2Executed);}private void SaveCommand2Executed(object? obj){}private void SaveCommandExecuted(object? obj){var bk = obj as Book;if (bk != null){System.Diagnostics.Debug.WriteLine(bk.ToString());}}private async Task InitBooksCollectionAsync(int cnt = 100000000){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> booksList = new List<Book>();for (int i = 1; i < cnt + 1; i++){booksList.Add(new Book(){Id = i,Name = $"Name_{i}",//ISBN=$"ISBN_{i}_{Guid.NewGuid()}",ImgUrl = $"{imgs[i % imgsCount]}"});if (i % 1000000 == 0){await PopulateBooksCollectionAsync(booksList);}}if (booksList.Any()){await PopulateBooksCollectionAsync(booksList);}}private async Task PopulateBooksCollectionAsync(List<Book> booksList){var tempList = booksList.ToList();booksList.Clear();await Application.Current.Dispatcher.InvokeAsync(() =>{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 = "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 (value != booksCollection){booksCollection = value;OnPropertyChanged();}}}public event PropertyChangedEventHandler? PropertyChanged;private void OnPropertyChanged([CallerMemberName] string propName = ""){var handler = PropertyChanged;handler?.Invoke(this, new PropertyChangedEventArgs(propName));}}public class GridBehavior : Behavior<Grid>{private ContextMenu contextMenu;public GridBehavior(){contextMenu = new ContextMenu();MenuItem mi = new MenuItem();mi.Header = "Save";mi.Click += Mi_Click;contextMenu.Items.Add(mi);}private void Mi_Click(object sender, RoutedEventArgs e){RightButtonSaveCommand?.Execute(CmdPara);}protected override void OnAttached(){base.OnAttached();AssociatedObject.ContextMenu = contextMenu;}protected override void OnDetaching(){base.OnDetaching();AssociatedObject.ContextMenu = null;}public ICommand RightButtonSaveCommand{get { return (ICommand)GetValue(RightButtonSaveCommandProperty); }set { SetValue(RightButtonSaveCommandProperty, value); }}// Using a DependencyProperty as the backing store for RightButtonSaveCommand.  This enables animation, styling, binding, etc...public static readonly DependencyProperty RightButtonSaveCommandProperty =DependencyProperty.Register(nameof(RightButtonSaveCommand), typeof(ICommand),typeof(GridBehavior), 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(GridBehavior), new PropertyMetadata(null));}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 ImgUrlConverter : IValueConverter{private Dictionary<string, ImageSource> imgCache = new Dictionary<string, ImageSource>();private static readonly object objLock = new object();public object Convert(object value, Type targetType, object parameter, CultureInfo culture){string imgUrl = value?.ToString();if (string.IsNullOrWhiteSpace(imgUrl) || !File.Exists(imgUrl)){return null;}lock (objLock){if (imgCache.TryGetValue(imgUrl, out ImageSource img)){return img;}using (FileStream fs = new FileStream(imgUrl, FileMode.Open, FileAccess.Read)){BitmapImage bmi = new BitmapImage();bmi.BeginInit();bmi.StreamSource = fs;bmi.CacheOption = BitmapCacheOption.OnLoad;bmi.EndInit();if (bmi.CanFreeze){bmi.Freeze();}imgCache.TryAdd(imgUrl, bmi);return bmi;}}}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 ISBN { get; set; }public string ImgUrl { get; set; }public override string ToString(){return $"{DateTime.Now},Id:{Id},Name:{Name},ISBN:{ISBN},ImgUrl:{ImgUrl}";}}
}

 

 

 

 

 

 

 

 

image

 

 

 

image

 

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

相关文章:

  • 状态机——协议的内在逻辑:用有限的状态,应对无限的世界
  • Vivado布线拥塞卡了8小时?手把手教你从Log到Device View定位K7 FPGA的Congestion元凶
  • 别再纠结硬件IIC了!用STM32的GPIO口手把手教你模拟IIC驱动AT24C16(附完整代码)
  • Unity场景管理进阶:除了LoadSceneAsync,你还需要知道的SetActiveScene和光照贴图处理
  • 告别Option键!在MacBook Pro 2015上,用rEFInd打造macOS与Ubuntu 20.04的无缝双系统切换
  • 别再死记硬背论文了!用Python+Transformer复现医学报告生成SOTA模型(附代码)
  • python的正则匹配
  • Mac Mouse Fix终极指南:如何让10美元鼠标超越苹果触控板
  • 2026年4月二次元冒险类游戏核心技术维度实测解析 - 优质品牌商家
  • Qwen3.5-9B-GGUF应用案例:研发团队API文档智能生成实测
  • 别再折腾nvidia-smi了!Jetson Xavier NX上,用jtop和APT一键搞定CUDA 10.2与cuDNN 8
  • 告别VSCode!在Sublime里用正则‘贪婪’与‘非贪婪’模式,高效整理代码注释和日志
  • GRBL固件源码深度解析:如何为你的DIY CNC雕刻机定制专属配置文件(以限位与主轴为例)
  • 手把手教你用STM32CubeMX配置SPI驱动DAC8563(HAL库实战,附完整代码)
  • 医学影像分割新宠UNet 3+:从论文到落地,我是如何用它提升肝脏分割Dice系数的
  • 矩阵运算类题型的问题
  • OpenCV实战:用连通域面积搞定工业品黑点粘连缺陷检测(附完整C++代码)
  • 嵌入式DSP并行计算与实时优化技术解析
  • K8S集群半夜告警,证书过期导致服务中断?保姆级修复流程(含kubeadm certs renew全解析)
  • 避坑指南:ESP32搭配百度TTS时,采样率设置不对声音就‘哑巴’了
  • 如何用OpenRocket免费火箭设计软件打造你的第一枚模型火箭 [特殊字符]
  • 方阵循环右移或左移类题型
  • Harepacker-resurrected终极指南:深度解析MapleStory游戏资源编辑全流程
  • 2026年q2可diy时装游戏排行:休闲养成手游土建/低配置能玩的二次元手游推荐/冒险类游戏推荐/选择指南 - 优质品牌商家
  • EF Core 10向量扩展上线踩坑实录:从本地POC到千万QPS生产集群的7大关键决策点
  • Win10远程桌面多开避坑指南:从gpedit.msc设置到关闭自动更新防失效
  • 5分钟掌握B站直播推流码获取:告别直播姬限制的完整指南
  • Jetson Nano离线/弱网环境部署指南:如何手动搞定jetson-inference的所有依赖(JetPack 4.6)
  • 郑州市春园婚姻介绍所:专业婚恋服务引领者,优质婚介与脱单服务的安心之选 - 海棠依旧大
  • tao-8k制造业知识库:设备手册长文本嵌入+故障描述语义匹配案例