






















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}"; } } }




此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。