WPF CutomControl ItemsControl.ItemsContainerStyle <Setter Property="FrameworkElement.HorizontalAlignment" Value="Stretch"/>

Install-Package Newtonsoft.json

  

//D:\C\WpfApp18\Models\Book.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace WpfApp18.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 CategoryName { get; set; }
        public string Summary { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
    }
}


//D:\C\WpfApp18\Themes\Generic.xaml
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApp18"
    xmlns:models="clr-namespace:WpfApp18.Models">


    <Style TargetType="{x:Type local:CustomItemsControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomItemsControl1}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="Cyan"
                            BorderThickness="2">
                        <ItemsControl ItemsSource="{Binding BooksCollection,RelativeSource={RelativeSource AncestorType=local:CustomItemsControl1}}"
                                      Margin="5,0"
                                      VirtualizingPanel.IsVirtualizing="True"
                                      VirtualizingPanel.VirtualizationMode="Recycling"
                                      VirtualizingPanel.CacheLength="5,5"
                                      VirtualizingPanel.CacheLengthUnit="Item"
                                      ScrollViewer.CanContentScroll="True"
                                      ScrollViewer.IsDeferredScrollingEnabled="True"
                                      HorizontalAlignment="Stretch"
                                      HorizontalContentAlignment="Stretch"
                                      >
                            <ItemsControl.ItemContainerStyle>
                                <Style>
                                    <Setter Property="FrameworkElement.HorizontalAlignment" Value="Stretch"/>
                                </Style>
                            </ItemsControl.ItemContainerStyle>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate DataType="{x:Type models:Book}">
                                    <Border BorderBrush="Cyan"
                                            BorderThickness="2"
                                            Margin="5,10"
                                            HorizontalAlignment="Stretch">
                                        <Grid Margin="5,5"
                                              HorizontalAlignment="Stretch">
                                            <Grid.Resources>
                                                <Style TargetType="TextBlock">
                                                    <Setter Property="FontSize" Value="20"/>
                                                    <Setter Property="HorizontalAlignment" Value="Center"/>
                                                    <Style.Triggers>
                                                        <Trigger Property="IsMouseOver" Value="True">
                                                            <Setter Property="Foreground" Value="Red"/>
                                                            <Setter Property="FontWeight" Value="ExtraBold"/>
                                                        </Trigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Grid.Resources>
                                            <Grid.RowDefinitions>
                                                <RowDefinition/>
                                                <RowDefinition/>
                                                <RowDefinition/>
                                            </Grid.RowDefinitions>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition/>
                                                <ColumnDefinition/>
                                                <ColumnDefinition/>
                                                <ColumnDefinition/>
                                            </Grid.ColumnDefinitions>
                                            <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Id}"/>
                                            <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"/>
                                            <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Author}"/>
                                            <TextBlock Grid.Row="0" Grid.Column="3" Text="{Binding Comment}"/>
                                            <TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding CategoryName}"/>
                                            <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Content}"/>
                                            <TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding Summary}"/>
                                            <TextBlock Grid.Row="1" Grid.Column="3" Text="{Binding Title}"/>
                                            <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding Topic}"/>
                                            <TextBlock Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding ISBN}"/>
                                        </Grid>
                                    </Border>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <VirtualizingStackPanel/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.Template>
                                <ControlTemplate>
                                    <ScrollViewer CanContentScroll="True">
                                        <ItemsPresenter HorizontalAlignment="Stretch"/>
                                    </ScrollViewer>
                                </ControlTemplate>
                            </ItemsControl.Template>
                        </ItemsControl>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


//D:\C\WpfApp18\CustomItemsControl1.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 WpfApp18.Models;

namespace WpfApp18
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfApp18"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:WpfApp18;assembly=WpfApp18"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:CustomItemsControl1/>
    ///
    /// </summary>
    public class CustomItemsControl1 : Control
    {
        static CustomItemsControl1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomItemsControl1), new FrameworkPropertyMetadata(typeof(CustomItemsControl1)));
        }





        public ObservableCollection<Book> BooksCollection
        {
            get { return (ObservableCollection<Book>)GetValue(BooksCollectionProperty); }
            set { SetValue(BooksCollectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BooksCollectionProperty =
            DependencyProperty.Register(nameof(BooksCollection),
                typeof(ObservableCollection<Book>),
                typeof(CustomItemsControl1),
                new PropertyMetadata(null));



    }
}


//D:\C\WpfApp18\MainWindow.xaml
<Window x:Class="WpfApp18.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:WpfApp18"
        mc:Ignorable="d"
        Title="{Binding MainTitle}"
        WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Grid>
        <local:CustomItemsControl1 
            BooksCollection="{Binding BksCollection}"
            HorizontalAlignment="Stretch"
            HorizontalContentAlignment="Stretch"/>
    </Grid>
</Window>


//D:\C\WpfApp18\MainWindow.xaml.cs
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net.Http;
using System.Reflection.Metadata;
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;
using WpfApp18.Models;

namespace WpfApp18
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        static string url = "http://172.16.107.152:5000/getbooks/1000000";
        static HttpClient client = new HttpClient()
        {
            Timeout = TimeSpan.FromMinutes(1)
        };
        static bool isLoading = false;

        public MainVM()
        {
            if(!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                _ = AutoLoadDataAsync();
            }
        }

        private async Task AutoLoadDataAsync()
        {
            while(true)
            {
                await LoadDataAsync();
                await Task.Delay(1000);
            }
        }

        private async Task LoadDataAsync()
        {
            if (isLoading)
            {
                return;
            }
            isLoading = true;

            MainTitle = $"{DateTime.Now},loading...";
            try
            {
                string jsonStr = await client.GetStringAsync(url);
                if (!string.IsNullOrWhiteSpace(jsonStr))
                {
                    var bks = JsonConvert.DeserializeObject<List<Book>>(jsonStr);
                    if (bks != null)
                    {
                        BksCollection = new ObservableCollection<Book>(bks);
                        MainTitle = $"{DateTime.Now},loaded {BksCollection.Count} items," +
                            $"FirstId:{BksCollection.FirstOrDefault()?.Id}," +
                            $"LastId:{BksCollection.LastOrDefault()?.Id}";
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
            }
            finally
            {
                isLoading = false;
            }
        }

        private ObservableCollection<Book> bksCollection;
        public ObservableCollection<Book> BksCollection
        {
            get
            {
                return bksCollection;
            }
            set
            {
                if (value != bksCollection)
                {
                    bksCollection = value;
                    OnPropertyChanged();
                }
            }
        }

        private string mainTitle = $"{DateTime.Now}";
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                if (value != mainTitle)
                {
                    mainTitle = 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));
            }
        }
    }
}

 

 

 

 

 

image

 

 

 

 

image

 

 

 

 

 

image

 

 

 

 

 

WebAPI

//D:\C\WebApplication9\Models\Book.cs
namespace WebApplication9.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 CategoryName { 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\WebApplication9\Controllers\BooksController.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WebApplication9.Models;

namespace WebApplication9.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)
        {
            List<Book> bksList = new List<Book>(cnt);
            var (start, end) = GetStartEnd(cnt);
            for (long i = start; i < end; i++)
            {
                bksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    Comment = $"Comment_{i}",
                    Content = $"Content_{i}",
                    Author = $"Author_{i}",
                    CategoryName = $"{enumNames[i % enumLen]}",
                    Summary = $"Summary_{i}",
                    Title = $"Title_{i}",
                    Topic = $"Topic_{i}"
                });
            }
            Console.WriteLine($"In WebAPI:{DateTime.Now},Start:{start},End:{end - 1}");
            return bksList;
        }
    }
}


//D:\C\WebApplication9\Program.cs

namespace WebApplication9
{
    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();
        }
    }
}

  

image

 

 

 

 

 

  

posted @ 2026-10-06 21:37  FredGrit  阅读(4)  评论(0)    收藏  举报