Install-Package Microsoft.Extensions.DependencyInjection;
Install-Package CommunityToolkit.mvvm;
//app.xaml <Application x:Class="WpfApp21.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfApp21"><Application.Resources></Application.Resources> </Application>//app.xaml.cs using Microsoft.Extensions.DependencyInjection; using System.Windows;namespace WpfApp21 {/// <summary>/// Interaction logic for App.xaml/// </summary>public partial class App : Application{ServiceProvider serviceProvider;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var services=new ServiceCollection();ConfigureServices(services);serviceProvider = services.BuildServiceProvider();var mainWin = serviceProvider.GetRequiredService<MainWindow>();mainWin?.Show();}private void ConfigureServices(ServiceCollection services){services.AddSingleton<INameService, NameService>();services.AddSingleton<IISBNService, ISBNService>();services.AddSingleton<IPriceService, PriceService>();services.AddSingleton<MainVM>();services.AddSingleton<MainWindow>();}protected override void OnExit(ExitEventArgs e){base.OnExit(e);serviceProvider?.Dispose();}}}//MainWindow.xaml <Window x:Class="WpfApp21.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"WindowState="Maximized"xmlns:local="clr-namespace:WpfApp21"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><!--DataTemplate for ListBox items--><DataTemplate x:Key="ItemTemplate"><Border Background="#FFE3F2FD"CornerRadius="0"Padding="10"Margin="2"><StackPanel Width="{Binding DataContext.GridWidth,RelativeSource={RelativeSource AncestorType=Window}}"Height="{Binding DataContext.GridHeight,RelativeSource={RelativeSource AncestorType=Window}}"><TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="50"/><TextBlock Text="{Binding ISBN}" FontSize="40" TextWrapping="Wrap"/><TextBlock Text="{Binding Price,StringFormat='C'}"Foreground="Green" FontWeight="Bold" FontSize="40" Margin="0,5,0,0"/></StackPanel></Border></DataTemplate><!--Custom ControlTemplate for ListBox--><ControlTemplate x:Key="lbxControlTemplate"TargetType="{x:Type ListBox}"><Border Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="10"><ScrollViewer Padding="{TemplateBinding Padding}"Focusable="False"><ItemsPresenter/></ScrollViewer></Border></ControlTemplate><!--Style for ListBox--><Style x:Key="CustomListBoxStyle"TargetType="{x:Type ListBox}"><Setter Property="Template" Value="{StaticResource lbxControlTemplate}"/><Setter Property="Background" Value="#FFF5F5F5"/><Setter Property="BorderBrush" Value="#FFBDBDBD"/><Setter Property="BorderThickness" Value="1"/><Setter Property="Padding" Value="5"/><!--<Setter Property="ScrollViewer.HorizontalBarVisibity" Value="Auto"/><Setter Property="ScrollViewer.VerticalBarVisibility" Value="Auto"/>--><Setter Property="ScrollViewer.CanContentScroll" Value="True"/><Setter Property="VerticalContentAlignment" Value="Stretch"/><Setter Property="ItemTemplate" Value="{StaticResource ItemTemplate}"/><Style.Triggers><Trigger Property="ItemsControl.AlternationIndex" Value="0"><Setter Property="Background" Value="#FFF5F5F5"/></Trigger><Trigger Property="ItemsControl.AlternationIndex" Value="1"><Setter Property="Background" Value="#FFFFFFFF"/></Trigger></Style.Triggers></Style><!--Style for ListBoxItem--><Style TargetType="{x:Type ListBoxItem}"><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="Padding" Value="4,2"/><Setter Property="HorizontalContentAlignment" Value="Stretch"/><Setter Property="VerticalContentAlignment" Value="Stretch"/><Setter Property="Background" Value="Transparent"/><Setter Property="BorderBrush" Value="Transparent"/><Setter Property="BorderThickness" Value="1"/><Setter Property="FocusVisualStyle" Value="{x:Null}"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ListBoxItem}"><Border x:Name="Bd"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="6"SnapsToDevicePixels="True"><ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}"SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/></Border><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="Bd" Property="Background" Value="#FFBBDEFB"/><Setter TargetName="Bd" Property="BorderBrush" Value="#FF64B5F6"/></Trigger><Trigger Property="IsSelected" Value="True"><Setter TargetName="Bd" Property="Background" Value="#FF2196F3"/><Setter TargetName="Bd" Property="BorderBrush" Value="#FF1976D2"/></Trigger><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsSelected" Value="True"/><Condition Property="IsMouseOver" Value="True"/></MultiTrigger.Conditions><Setter TargetName="Bd" Property="Background" Value="#FF1976D2"/><Setter TargetName="Bd" Property="BorderBrush" Value="#FF0D47A1"/></MultiTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></Window.Resources><Grid><ListBox x:Name="customLbx"Style="{StaticResource CustomListBoxStyle}"ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"SelectionMode="Extended"Margin="20"> </ListBox></Grid> </Window>//MainWindow.xaml.cs using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.ObjectModel; using System.Windows;namespace WpfApp21 {/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}public MainWindow(MainVM vm){InitializeComponent();this.DataContext=vm;this.SizeChanged+=MainWindow_SizeChanged;}private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e){if (this.DataContext is MainVM vm){var fe = this.Content as FrameworkElement;if (fe!=null){vm.GridWidth=fe.ActualWidth;vm.GridHeight=fe.ActualHeight/5;}}}}public partial class MainVM : ObservableObject{private INameService nameService;private IISBNService isbnService;private IPriceService priceService;public MainVM(INameService nameServiceValue, IISBNService isbnServiceValue, IPriceService priceServiceValue){nameService= nameServiceValue;isbnService= isbnServiceValue;priceService= priceServiceValue;InitItems();}private void InitItems(){BooksCollection=new ObservableCollection<Book>();for (int i = 0; i<100; i++){BooksCollection.Add(new Book(){Name=nameService.GetName(),ISBN=isbnService.GetISBN(),Price=priceService.GetPrice()});}}[ObservableProperty]private ObservableCollection<Book> booksCollection;[ObservableProperty]private double gridWidth;[ObservableProperty]private double gridHeight;}public class Book{public string Name { get; set; }public string ISBN { get; set; }public decimal Price { get; set; }}public interface INameService{string GetName();}public class NameService : INameService{int idx = 0;public string GetName(){return $"Name_{Interlocked.Increment(ref idx)}";}}public interface IISBNService{string GetISBN();}public class ISBNService : IISBNService{int idx = 0;public string GetISBN(){return $"ISBN_{Interlocked.Increment(ref idx)}_{Guid.NewGuid():N}";}}public interface IPriceService{decimal GetPrice();}public class PriceService : IPriceService{Random rnd = new Random();public decimal GetPrice(){return (decimal)rnd.NextDouble()*100;}}}