WPF transfer between main view and sub views, selected in main view and edit in editing view, then save and display the latest result in main view
get-project -all|Install-Package Newtonsoft.json get-project -all|Install-Package Microsoft.Xaml.Behaviors.WPF
WPFControl and WPFFramework build as class library, be added to other project.
//WPFFramework
//D:\C\WPFFramework\Common\DelegateCommand.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace WPFFramework.Common
{
public class DelegateCommand : ICommand
{
private readonly Action<object?> execute;
private readonly Func<object?, bool>? canExecute;
public DelegateCommand(Action<object?> executeValue, Func<object?, bool>? canExecuteValue = null)
{
execute = executeValue ?? throw new ArgumentNullException(nameof(executeValue));
canExecute = canExecuteValue;
}
public event EventHandler? CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var handler = Volatile.Read(ref CanExecuteChanged);
if (handler != null)
{
var dispathcer = Application.Current?.Dispatcher;
if (dispathcer != null)
{
if (dispathcer.CheckAccess())
{
handler(this, EventArgs.Empty);
}
else
{
dispathcer.Invoke(() =>
{
handler(this, EventArgs.Empty);
}, System.Windows.Threading.DispatcherPriority.Background);
}
}
}
}
public bool CanExecute(object? parameter)
{
return canExecute == null ? true : canExecute(parameter);
}
public void Execute(object? parameter)
{
execute(parameter);
}
}
}
//D:\C\WPFFramework\Common\ViewModelBase.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
namespace WPFFramework.Common
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propName="")
{
var handler = Volatile.Read(ref PropertyChanged);
if(handler!=null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
}
}
//WPFControl
//D:\C\WPF2Control\Book.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Text; using System.Windows.Controls; namespace WPF2Control { public class Book: INotifyPropertyChanged { public long Id { get; set; } private string name; public string Name { get { return name; } set { if(value!=name) { name = value; OnPropertyChanged(); } } } private string isbn; public string ISBN { get { return isbn; } set { if (value != isbn) { isbn = value; OnPropertyChanged(); } } } private string author; public string Author { get { return author; } set { if(value!=author) { author = value; OnPropertyChanged(); } } } private string comment; public string Comment { get { return comment; } set { if(value!=comment) { comment = value; OnPropertyChanged(); } } } private string content; public string Content { get { return content; } set { if(value!=content) { content = value; OnPropertyChanged(); } } } private string summary; public string Summary { get { return summary; } set { if(value!=summary) { summary = value; OnPropertyChanged(); } } } private string title; public string Title { get { return title; } set { if (value != title) { title = value; OnPropertyChanged(); } } } private string topic; public string Topic { get { return topic; } set { if(value!=topic) { topic = value; OnPropertyChanged(); } } } private string categoryName; public string CategoryName { get { return categoryName; } set { if(value!=categoryName) { categoryName = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propName="") { var handler = Volatile.Read(ref PropertyChanged); if(handler!=null) { handler(this, new PropertyChangedEventArgs(propName)); } } public Book Clone() { return new Book() { Id = this.Id, Name = this.Name, ISBN = this.ISBN, Author = this.Author, Comment = this.Comment, Content = this.Content, Summary = this.Summary, Title = this.Title, Topic = this.Topic, CategoryName = this.CategoryName }; } } } //D:\C\WPF2Control\MainView.xaml <UserControl x:Class="WPF2Control.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPF2Control" xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.DataContext> <local:MainViewModel/> </UserControl.DataContext> <UserControl.Resources> <Style TargetType="DataGrid"> <Setter Property="SelectionMode" Value="Extended"/> <Setter Property="UseLayoutRounding" Value="True"/> <Setter Property="AutoGenerateColumns" Value="False"/> <Setter Property="CanUserAddRows" Value="False"/> <Setter Property="HeadersVisibility" Value="Column"/> <Setter Property="FontSize" Value="20"/> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="BorderThickness" Value="1"/> </Style> <Style TargetType="DataGridRow"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Red"/> <Setter Property="FontWeight" Value="SemiBold"/> </Trigger> </Style.Triggers> </Style> </UserControl.Resources> <Grid> <DataGrid ItemsSource="{Binding BksCollection}" IsReadOnly="True" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="5,5" VirtualizingPanel.CacheLengthUnit="Item" ScrollViewer.CanContentScroll="True" ScrollViewer.IsDeferredScrollingEnabled="True"> <DataGrid.Columns> <DataGridTextColumn Header="Id" Binding="{Binding Id}"/> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> <DataGridTextColumn Header="ISBN" Binding="{Binding ISBN}"/> <DataGridTextColumn Header="Author" Binding="{Binding Author}"/> <DataGridTextColumn Header="Comment" Binding="{Binding Comment}"/> <DataGridTextColumn Header="Content" Binding="{Binding Content}"/> <DataGridTextColumn Header="Summary" Binding="{Binding Summary}"/> <DataGridTextColumn Header="Title" Binding="{Binding Title}"/> <DataGridTextColumn Header="Topic" Binding="{Binding Topic}"/> <DataGridTextColumn Header="CategoryName" Binding="{Binding CategoryName}"/> </DataGrid.Columns> <DataGrid.ContextMenu> <ContextMenu> <MenuItem Header="Edit Selected" Command="{Binding EditSelectedCommand}" FontSize="20" Width="300"/> </ContextMenu> </DataGrid.ContextMenu> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="SelectionChanged"> <behavior:InvokeCommandAction Command="{Binding SelectionChangedCommand}" PassEventArgsToCommand="True"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> </DataGrid> </Grid> </UserControl> //D:\C\WPF2Control\MainViewModel.cs using System; using System.Collections.Generic; using System.Net.Http; using System.Text; using System.Windows; using WPFFramework.Common; using Newtonsoft.Json; using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Input; using System.Windows.Controls; namespace WPF2Control { public class MainViewModel : ViewModelBase { static string url = "http://172.17.0.184:5000/getbooks/1000000"; static HttpClient client = new HttpClient() { Timeout = TimeSpan.FromMinutes(1) }; private Window editWin; public MainViewModel() { if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) { _ = LoadDataAsync(); } } private async Task LoadDataAsync() { try { string jsonStr = await client.GetStringAsync(url); if (!string.IsNullOrWhiteSpace(jsonStr)) { var bks = JsonConvert.DeserializeObject<List<Book>>(jsonStr); if (bks != null && bks.Any()) { BksCollection = new ObservableCollection<Book>(bks); } } } catch (Exception ex) { MessageBox.Show(ex?.Message); } } private ICommand saveCommand; public ICommand SaveCommand { get { if (saveCommand == null) { saveCommand = new DelegateCommand(SaveCommandExecuted); } return saveCommand; } } private void SaveCommandExecuted(object? obj) { if (editWin != null) { editWin.DialogResult = true; editWin.Close(); } } private ICommand cancelCommand; public ICommand CancelCommand { get { if (cancelCommand == null) { cancelCommand = new DelegateCommand(CancelCommandExecuted); } return cancelCommand; } } private void CancelCommandExecuted(object? obj) { editWin.DialogResult = false; editWin.Close(); } private ICommand editSelectedCommand; public ICommand EditSelectedCommand { get { if (editSelectedCommand == null) { editSelectedCommand = new DelegateCommand(EditSelectedCommandExecuted); } return editSelectedCommand; } } private void EditSelectedCommandExecuted(object? obj) { ShowEditWindow(); } private ICommand selectionChangedCommand; public ICommand SelectionChangedCommand { get { if (selectionChangedCommand == null) { selectionChangedCommand = new DelegateCommand(SelectionChangedCommandExecuted); } return selectionChangedCommand; } } private void SelectionChangedCommandExecuted(object? obj) { var e = obj as SelectionChangedEventArgs; if (e != null) { var dg = e.OriginalSource as DataGrid; if (dg != null) { selectedItems = dg.SelectedItems.Cast<Book>()?.ToList(); } } } private void ShowEditWindow() { if (selectedItems != null && selectedItems.Any()) { SelectedBks = new ObservableCollection<Book>(selectedItems.Select(x => x.Clone()).ToList()); EditView editView = new EditView(); editView.DataContext = this; editWin = new Window() { Title = "Edit View" }; editWin.Content = editView; if (editWin.ShowDialog() == true) { if (SelectedBks != null && SelectedBks.Any()) { foreach (var bk in SelectedBks) { var oldBk = BksCollection.Where(x => x.Id == bk.Id).FirstOrDefault(); if (oldBk != null) { var idx = BksCollection.IndexOf(oldBk); BksCollection.Remove(oldBk); BksCollection.Insert(idx, bk); } } } } } } private List<Book> selectedItems = new List<Book>(); private ObservableCollection<Book> selectedBks; public ObservableCollection<Book> SelectedBks { get { return selectedBks; } set { if (value != selectedBks) { selectedBks = value; OnPropertyChanged(); } } } private ObservableCollection<Book> bksCollection; public ObservableCollection<Book> BksCollection { get { return bksCollection; } set { if (value != bksCollection) { bksCollection = value; OnPropertyChanged(); } } } } } //D:\C\WPF2Control\EditView.xaml <UserControl x:Class="WPF2Control.EditView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPF2Control" xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.Resources> <Style TargetType="DataGrid"> <Setter Property="SelectionMode" Value="Extended"/> <Setter Property="UseLayoutRounding" Value="True"/> <Setter Property="AutoGenerateColumns" Value="False"/> <Setter Property="CanUserAddRows" Value="False"/> <Setter Property="HeadersVisibility" Value="Column"/> <Setter Property="FontSize" Value="20"/> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="BorderThickness" Value="1"/> </Style> <Style TargetType="DataGridRow"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Red"/> <Setter Property="FontWeight" Value="SemiBold"/> </Trigger> </Style.Triggers> </Style> <Style TargetType="Button"> <Setter Property="FontSize" Value="20"/> <Setter Property="Margin" Value="20,2"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Width" Value="100"/> <Setter Property="Height" Value="30"/> </Style> </UserControl.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <DataGrid ItemsSource="{Binding SelectedBks}" Grid.Row="0" IsReadOnly="False" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="5,5" VirtualizingPanel.CacheLengthUnit="Item" ScrollViewer.CanContentScroll="True" ScrollViewer.IsDeferredScrollingEnabled="True"> <DataGrid.Columns> <DataGridTextColumn Header="Id" Binding="{Binding Id}" IsReadOnly="True"/> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> <DataGridTextColumn Header="ISBN" Binding="{Binding ISBN}" Width="*"/> <DataGridTextColumn Header="Author" Binding="{Binding Author}"/> <DataGridTextColumn Header="Comment" Binding="{Binding Comment}"/> <DataGridTextColumn Header="Content" Binding="{Binding Content}"/> <DataGridTextColumn Header="Summary" Binding="{Binding Summary}"/> <DataGridTextColumn Header="Title" Binding="{Binding Title}"/> <DataGridTextColumn Header="Topic" Binding="{Binding Topic}"/> <DataGridTextColumn Header="CategoryName" Binding="{Binding CategoryName}"/> </DataGrid.Columns> <DataGrid.ContextMenu> <ContextMenu> <MenuItem Header="Edit Selected" Command="{Binding EditSelectedCommand}" FontSize="20" Width="300"/> </ContextMenu> </DataGrid.ContextMenu> </DataGrid> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="150"/> <ColumnDefinition Width="150"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Button Grid.Column="1" Content="Save" Command="{Binding SaveCommand}"/> <Button Grid.Column="2" Content="Cancel" Command="{Binding CancelCommand}"/> </Grid> </Grid> </UserControl>
//WPFMain
//D:\C\WpfApp2\MainWindow.xaml <Window x:Class="WpfApp2.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:WpfApp2" xmlns:controls="clr-namespace:WPF2Control;assembly=WPF2Control" mc:Ignorable="d" Title="MainWindow" WindowState="Maximized"> <Grid> <controls:MainView/> </Grid> </Window>
private void SelectionChangedCommandExecuted(object? obj)
{
var e = obj as SelectionChangedEventArgs;
if (e != null)
{
var dg = e.OriginalSource as DataGrid;
if (dg != null)
{
selectedItems = dg.SelectedItems.Cast<Book>()?.ToList();
}
}
}
private void ShowEditWindow()
{
if (selectedItems != null && selectedItems.Any())
{
SelectedBks = new ObservableCollection<Book>(selectedItems.Select(x => x.Clone()).ToList());
EditView editView = new EditView();
editView.DataContext = this;
editWin = new Window()
{
Title = "Edit View"
};
editWin.Content = editView;
if (editWin.ShowDialog() == true)
{
if (SelectedBks != null && SelectedBks.Any())
{
foreach (var bk in SelectedBks)
{
var oldBk = BksCollection.Where(x => x.Id == bk.Id).FirstOrDefault();
if (oldBk != null)
{
var idx = BksCollection.IndexOf(oldBk);
BksCollection.Remove(oldBk);
BksCollection.Insert(idx, bk);
}
}
}
}
}
}




//ASP.Net Core WebAPI
//D:\C\WebApplication2\Models\Book.cs
namespace WebApplication2.Models
{
public class Book
{
public long Id { get; set; }
public string Name { get; set; }
public string ISBN { 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; }
public string CategoryName { get; set; }
}
enum BookCategory
{
Science, Technology, Engineering, Math
}
}
//D:\C\WebApplication2\Controllers\BooksController.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WebApplication2.Models;
namespace WebApplication2.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private static string[] enumNames = Enum.GetNames(typeof(BookCategory));
private static int enumLen = enumNames.Length;
private static long id = 1;
private static (long, long) GetStartEnd(int cnt = 1000000)
{
long end = Interlocked.Add(ref id, cnt);
long start = end - cnt;
return (start, end);
}
[HttpGet("/getbooks/{cnt}")]
public List<Book> GetBooks(int cnt = 1000000)
{
var (start, end) = GetStartEnd(cnt);
List<Book> bksList = new List<Book>(cnt);
for (long i = start; i < end; i++)
{
bksList.Add(new Book()
{
Id = i,
Name = $"Name_{i}",
Author = $"Author_{i}",
Comment = $"Comment_{i}",
Content = $"Content_{i}",
CategoryName = $"{enumNames[i % enumLen]}",
ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
Summary = $"Summary_{i}",
Title = $"Title_{i}",
Topic = $"Topic_{i}"
});
}
return bksList;
}
}
}
//D:\C\WebApplication2\Program.cs
namespace WebApplication2
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(x =>
{
x.ListenAnyIP(5000);
x.ListenAnyIP(5001, o =>
{
o.UseHttps();
});
});
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}

浙公网安备 33010602011771号