WPF DataGrid DataGridTemplateColumn DataTemplate call predefined DataTemplate via ContentPresenter and ContentTemplate
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter ContentTemplate="{StaticResource BookDataTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
//WPF
Install-Package Newtonsoft.Json
//D:\C\WpfApp7\MainWindow.xaml <Window x:Class="WpfApp7.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:WpfApp7" mc:Ignorable="d" Title="{Binding MainTitle}" WindowState="Maximized"> <Window.DataContext> <local:MainVM/> </Window.DataContext> <Window.Resources> <Style TargetType="TextBlock" x:Key="TbkStyle"> <Setter Property="FontSize" Value="30"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Red"/> <Setter Property="FontWeight" Value="ExtraBold"/> </Trigger> </Style.Triggers> </Style> <DataTemplate DataType="{x:Type local:Book}" x:Key="BookDataTemplate"> <Grid Margin="10" Width="{x:Static SystemParameters.PrimaryScreenWidth}"> <Grid.Resources> <Style TargetType="TextBlock" BasedOn="{StaticResource TbkStyle}"/> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition MaxWidth="300"/> <ColumnDefinition MaxWidth="300"/> <ColumnDefinition Width="*"/> </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="0" Grid.Column="2"/> <TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="0"/> <TextBlock Text="{Binding Comment}" Grid.Row="1" Grid.Column="1"/> <TextBlock Text="{Binding Content}" Grid.Row="1" Grid.Column="2"/> <TextBlock Text="{Binding Summary}" Grid.Row="2" Grid.Column="0"/> <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="1"/> <TextBlock Text="{Binding Topic}" Grid.Row="2" Grid.Column="2"/> </Grid> </DataTemplate> <ControlTemplate TargetType="ContentControl" x:Key="DGTemplate"> <DataGrid ItemsSource="{Binding BksCollection}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="5,5" VirtualizingPanel.CacheLengthUnit="Item" ScrollViewer.CanContentScroll="True" ScrollViewer.IsDeferredScrollingEnabled="True" AutoGenerateColumns="False" CanUserAddRows="False" SnapsToDevicePixels="True" UseLayoutRounding="True"> <DataGrid.Columns> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ContentPresenter ContentTemplate="{StaticResource BookDataTemplate}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </ControlTemplate> </Window.Resources> <Grid> <ContentControl Template="{StaticResource DGTemplate}"/> </Grid> </Window> //D:\C\WpfApp7\MainWindow.xaml.cs using Newtonsoft.Json; using System.Collections.ObjectModel; using System.ComponentModel; 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 WpfApp7 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class MainVM : INotifyPropertyChanged { private static string url = "https://localhost:5001/api/books/getbooks/"; private static HttpClient client = new HttpClient() { Timeout = TimeSpan.FromHours(1) }; private bool isLoading = false; public MainVM() { if(!DesignerProperties.GetIsInDesignMode(new DependencyObject())) { _ = AutoLoadDataAsync(); } } private async Task AutoLoadDataAsync(int cnt=1000000) { while(true) { await InitBksAsync(); await Task.Delay(5000); } } private async Task InitBksAsync(int cnt=1000000) { if(isLoading) { return; } isLoading = false; MainTitle = $"{DateTime.Now},loading..."; PrintMsg(MainTitle); try { string jsonStr = await client.GetStringAsync($"{url}{cnt}"); var bks = JsonConvert.DeserializeObject<List<Book>>(jsonStr); if (bks != null && bks.Any()) { BksCollection = new ObservableCollection<Book>(bks); MainTitle = $"{DateTime.Now},length:{BksCollection.Count},FirstId:{BksCollection.FirstOrDefault()?.Id},LastId:{BksCollection.LastOrDefault()?.Id}"; PrintMsg(MainTitle); } } catch (Exception ex) { MessageBox.Show(ex?.Message); } finally { isLoading = false; } } private void PrintMsg(string msg) { #if DEBUG System.Diagnostics.Debug.WriteLine(msg); #else System.Diagnostics.Trace.WriteLine(msg); #endif } private string mainTitle = $"{DateTime.Now}"; public string MainTitle { get { return mainTitle; } set { if(value!=mainTitle) { mainTitle = value; OnPropertyChanged(); } } } private ObservableCollection<Book> bksCollection; public ObservableCollection<Book> BksCollection { get { return bksCollection; } set { if(value!=bksCollection) { bksCollection = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged([CallerMemberName]string propName="") { var handler=Volatile.Read(ref PropertyChanged); if(handler==null) { return; } handler(this, new PropertyChangedEventArgs(propName)); } } public class Book { public long Id { get; set; } public string Name { get; set; } public string Author { get; set; } public string CategoryName { get; set; } public string ISBN { 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; } } }
//Asp.Net WebAPI plays as data provider and Kestrel as service host.
//D:\C\WebApplication3\Models\Book.cs namespace WebApplication3.Models { public class Book { public long Id { get; set; } public string Name { get; set; } public string Author { get; set; } public string CategoryName { get; set; } public string ISBN { 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; } } enum BookCategory { Science, Technology, Engineering, Math } } //D:\C\WebApplication3\Controllers\BooksController.cs using Microsoft.AspNetCore.Mvc; using WebApplication3.Models; // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 namespace WebApplication3.Controllers { [Route("api/[controller]")] [ApiController] public class BooksController : ControllerBase { private static long id = 1; private static string[] enumNames = Enum.GetNames(typeof(BookCategory)); private static int enumsLen=enumNames.Length; 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) { List<Book> bksList=new List<Book>(); var(start,end) = GetStartEnd(cnt); for(long i=start;i<end;i++) { bksList.Add(new Book() { Id=i, Name=$"Name_{i}", CategoryName = $"{enumNames[i%enumsLen]}", Author=$"Author_{i}", Comment=$"Comment_{i}", Content=$"Content_{i}", Summary=$"Summary_{i}", ISBN=$"ISBN_{i}_{Guid.NewGuid():N}", Title=$"Title_{i}", Topic=$"Topic_{i}" }); } Console.WriteLine($"{DateTime.Now},Length:{cnt}," + $"First Id:{bksList.FirstOrDefault()?.Id}," + $"Last Id:{bksList.LastOrDefault()?.Id}"); return bksList; } } } //D:\C\WebApplication3\Program.cs namespace WebApplication3 { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseKestrel(options => { options.ListenLocalhost(5000); options.ListenLocalhost(5001, x => { x.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(); } } }


info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production info: Microsoft.Hosting.Lifetime[0] Content root path: D:\C\WebApplication3\bin\Release\net10.0 2026-09-05 17:27:03,Length:1000000,First Id:1,Last Id:1000000 2026-09-05 17:27:34,Length:1000000,First Id:1000001,Last Id:2000000 2026-09-05 17:28:07,Length:1000000,First Id:2000001,Last Id:3000000 2026-09-05 17:29:34,Length:1000000,First Id:3000001,Last Id:4000000 2026-09-05 17:29:44,Length:1000000,First Id:4000001,Last Id:5000000 2026-09-05 17:29:53,Length:1000000,First Id:5000001,Last Id:6000000 2026-09-05 17:30:03,Length:1000000,First Id:6000001,Last Id:7000000 2026-09-05 17:30:12,Length:1000000,First Id:7000001,Last Id:8000000 2026-09-05 17:30:23,Length:1000000,First Id:8000001,Last Id:9000000 2026-09-05 17:30:36,Length:1000000,First Id:9000001,Last Id:10000000 2026-09-05 17:30:49,Length:1000000,First Id:10000001,Last Id:11000000 2026-09-05 17:31:03,Length:1000000,First Id:11000001,Last Id:12000000 2026-09-05 17:31:16,Length:1000000,First Id:12000001,Last Id:13000000 2026-09-05 17:31:30,Length:1000000,First Id:13000001,Last Id:14000000 2026-09-05 17:31:43,Length:1000000,First Id:14000001,Last Id:15000000 2026-09-05 17:31:57,Length:1000000,First Id:15000001,Last Id:16000000 2026-09-05 17:32:11,Length:1000000,First Id:16000001,Last Id:17000000 2026-09-05 17:32:23,Length:1000000,First Id:17000001,Last Id:18000000 2026-09-05 17:32:37,Length:1000000,First Id:18000001,Last Id:19000000 2026-09-05 17:32:50,Length:1000000,First Id:19000001,Last Id:20000000 2026-09-05 17:33:05,Length:1000000,First Id:20000001,Last Id:21000000 2026-09-05 17:33:17,Length:1000000,First Id:21000001,Last Id:22000000 2026-09-05 17:33:32,Length:1000000,First Id:22000001,Last Id:23000000 2026-09-05 17:33:45,Length:1000000,First Id:23000001,Last Id:24000000 2026-09-05 17:33:59,Length:1000000,First Id:24000001,Last Id:25000000 2026-09-05 17:34:12,Length:1000000,First Id:25000001,Last Id:26000000 2026-09-05 17:34:26,Length:1000000,First Id:26000001,Last Id:27000000 2026-09-05 17:34:40,Length:1000000,First Id:27000001,Last Id:28000000 2026-09-05 17:34:49,Length:1000000,First Id:28000001,Last Id:29000000 2026-09-05 17:35:03,Length:1000000,First Id:29000001,Last Id:30000000 2026-09-05 17:35:13,Length:1000000,First Id:30000001,Last Id:31000000


浙公网安备 33010602011771号