

























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




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