<DataGrid.ContextMenu><ContextMenu><MenuItem Header="{Binding FirstMIHeader}"FontSize="50"Width="350"Height="150"Command="{Binding FirstCmd}"CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},Path=PlacementTarget.SelectedItems}"/></ContextMenu></DataGrid.ContextMenu>private DelCmd firstCmd; public DelCmd FirstCmd {get{if (firstCmd == null){firstCmd = new DelCmd(FirstCmdExecuted);}return firstCmd;} }private void FirstCmdExecuted(object? obj) {_ = Task.Run(async() =>{var items = ((System.Collections.IList)obj).Cast<Book>()?.ToList();if (items != null && items.Any()){string jsonStr = JsonConvert.SerializeObject(items, Formatting.Indented);string jsonFile = string.Empty;await Application.Current?.Dispatcher?.InvokeAsync(() =>{SaveFileDialog dlg = new SaveFileDialog();dlg.Filter = $"Json Files|*.json";dlg.FileName = $"Json_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";if (dlg.ShowDialog() == true){jsonFile = dlg.FileName;}});using(StreamWriter jsonWriter=new StreamWriter(jsonFile,false,Encoding.UTF8)){jsonWriter.WriteLine(jsonStr);}await Application.Current?.Dispatcher?.InvokeAsync(() =>{MessageBox.Show($"Saved {items.Count} items in {jsonFile}");},System.Windows.Threading.DispatcherPriority.Background);}}); }private string firstMIHeader="Save In Json"; public string FirstMIHeader {get{return firstMIHeader;}set{if (value != firstMIHeader){firstMIHeader = value;OnPropertyChanged();}} }
Install-Package Newtonsoft.json
<Window x:Class="WpfApp10.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:WpfApp10"mc:Ignorable="d"Title="{Binding MainTitle}" WindowState="Maximized"><Window.DataContext><local:MainVM/></Window.DataContext><Grid><DataGrid ItemsSource="{Binding BooksCollection}"VirtualizingPanel.IsVirtualizing="True"VirtualizingPanel.VirtualizationMode="Recycling"VirtualizingPanel.CacheLength="5,5"VirtualizingPanel.CacheLengthUnit="Item"ScrollViewer.IsDeferredScrollingEnabled="True"ScrollViewer.CanContentScroll="True"UseLayoutRounding="True"SnapsToDevicePixels="True"CanUserAddRows="False"AutoGenerateColumns="True"EnableRowVirtualization="True"EnableColumnVirtualization="True"><DataGrid.Resources><Style TargetType="DataGridRow"><Setter Property="FontSize" Value="30"/><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="FontSize" Value="40"/><Setter Property="Foreground" Value="Red"/></Trigger></Style.Triggers></Style></DataGrid.Resources><DataGrid.ContextMenu><ContextMenu><MenuItem Header="{Binding FirstMIHeader}"FontSize="50"Width="350"Height="150"Command="{Binding FirstCmd}"CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},Path=PlacementTarget.SelectedItems}"/></ContextMenu></DataGrid.ContextMenu></DataGrid></Grid> </Window>using Microsoft.Win32; using Newtonsoft.Json; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Net.Http; 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 WpfApp10 {/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}}public class MainVM : INotifyPropertyChanged{string originUrl = "http://localhost:51537/BookService.svc/getbookslist?cnt=";static readonly HttpClient client = new HttpClient();private readonly object isLoadingLock = new object();private readonly SemaphoreSlim semaphoreThrottle = new SemaphoreSlim(10, 10);public MainVM(){if (DesignerProperties.GetIsInDesignMode(new DependencyObject())){return;}_ = Task.Run(async () =>{while (true){await InitBooksCollectionAsync();await Task.Delay(20000);}});}private async Task InitBooksCollectionAsync(int cnt = 1000000){if (!await semaphoreThrottle.WaitAsync(20000)){return;}if (IsLoading){return;}IsLoading = true;try{await Application.Current?.Dispatcher?.InvokeAsync(() =>{MainTitle = $"{DateTime.Now},loading...";}, System.Windows.Threading.DispatcherPriority.Background);string requestUrl = $"{originUrl}{cnt}";await Task.Run(async () =>{string jsonStr = await client.GetStringAsync(requestUrl);if (string.IsNullOrWhiteSpace(jsonStr)){return;}List<Book>? bks = JsonConvert.DeserializeObject<List<Book>>(jsonStr);if (bks != null && bks.Any()){await Application.Current?.Dispatcher?.InvokeAsync(() =>{BooksCollection = new ObservableCollection<Book>(bks);MainTitle = $"{DateTime.Now},FirstID:{BooksCollection.FirstOrDefault()?.Id},LastID:{BooksCollection.LastOrDefault()?.Id}";}, System.Windows.Threading.DispatcherPriority.Background);}});}catch (Exception ex){MessageBox.Show($"{DateTime.Now},exception message {ex?.Message}");}finally{IsLoading = false;semaphoreThrottle.Release();}}private DelCmd firstCmd;public DelCmd FirstCmd{get{if (firstCmd == null){firstCmd = new DelCmd(FirstCmdExecuted);}return firstCmd;}}private void FirstCmdExecuted(object? obj){_ = Task.Run(async() =>{var items = ((System.Collections.IList)obj).Cast<Book>()?.ToList();if (items != null && items.Any()){string jsonStr = JsonConvert.SerializeObject(items, Formatting.Indented);string jsonFile = string.Empty;await Application.Current?.Dispatcher?.InvokeAsync(() =>{SaveFileDialog dlg = new SaveFileDialog();dlg.Filter = $"Json Files|*.json";dlg.FileName = $"Json_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";if (dlg.ShowDialog() == true){jsonFile = dlg.FileName;}});using(StreamWriter jsonWriter=new StreamWriter(jsonFile,false,Encoding.UTF8)){jsonWriter.WriteLine(jsonStr);}await Application.Current?.Dispatcher?.InvokeAsync(() =>{MessageBox.Show($"Saved {items.Count} items in {jsonFile}");},System.Windows.Threading.DispatcherPriority.Background);}}); }private string firstMIHeader="Save In Json";public string FirstMIHeader{get{return firstMIHeader;}set{if (value != firstMIHeader){firstMIHeader = value;OnPropertyChanged();}}}private bool isLoading = false;public bool IsLoading{get{lock (isLoadingLock){return isLoading;}}set{lock (isLoadingLock){if (value != isLoading){isLoading = value;OnPropertyChanged();}}}}private string mainTitle = $"{DateTime.Now}";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 = Volatile.Read(ref PropertyChanged);if (handler == null){return;}handler?.Invoke(this, new PropertyChangedEventArgs(propName));}}public class DelCmd : ICommand{private readonly Action<object?> execute;private readonly Func<object?, bool>? canExecute;public DelCmd(Action<object?> executeValue, Func<object?, bool>? canExecuteValue = null){execute = executeValue;canExecute = canExecuteValue;}public event EventHandler? CanExecuteChanged;public bool CanExecute(object? parameter){return canExecute == null ? true : canExecute(parameter);}public void Execute(object? parameter){if (!CanExecute(parameter)){return;}execute?.Invoke(parameter);}public void RaiseCanExecuteChanged(object? parameter){var handler = Volatile.Read(ref CanExecuteChanged);if (handler == null){return;}if (Application.Current?.Dispatcher?.CheckAccess() == true){handler?.Invoke(parameter, EventArgs.Empty);}else{Application.Current?.Dispatcher?.Invoke(() =>{handler?.Invoke(parameter, EventArgs.Empty);});}}}public class Book{public long Id { get; set; }public string Name { get; set; }public string ISBN { get; set; }public string Abstract { get; set; }public string Author { get; set; }public string Comment { get; set; }public string Content { get; set; }public string Summary { get; set; }public string Title { get; set; }public string Topic { get; set; }}}


