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;
}
}
}
![image]()
![image]()