WPF Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting;

Install-Package CommunityToolkit.MVVM;
Install-Package Microsoft.Extensions.DependencyInjection;
Install-Package Microsoft.Extensions.Hosting;

 

//xaml

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="LBXDataTemplate">
            <Grid Width="{Binding DataContext.GridWidth,RelativeSource={RelativeSource AncestorType=Window}}"
                  Height="{Binding DataContext.GridHeight,RelativeSource={RelativeSource AncestorType=Window}}">
                <Grid.Resources>
                    <Style TargetType="ColumnDefinition">
                        <Setter Property="Width" Value="Auto"/>
                    </Style>
                    <Style TargetType="TextBlock">
                        <Setter Property="FontSize" Value="30"/>
                        <Setter Property="FontWeight" Value="Bold"/>
                        <Setter Property="HorizontalAlignment" Value="Center"/>
                        <Setter Property="VerticalAlignment" Value="Center"/>
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="FontSize" Value="50"/>
                                <Setter Property="Foreground" Value="Red"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Resources>
                <Grid.Background>
                    <ImageBrush ImageSource="{Binding ImgSource}"/>
                </Grid.Background>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Id}"/>
                <TextBlock Grid.Column="1" Text="{Binding Name}"/>
                <TextBlock Grid.Column="2" Text="{Binding Author}"/>
                <TextBlock Grid.Column="3" Text="{Binding Comment}"/>
                <TextBlock Grid.Column="4" Text="{Binding Content}"/>
                <TextBlock Grid.Column="5" Text="{Binding Summary}"/>
                <TextBlock Grid.Column="6" Text="{Binding Title}"/>
                <TextBlock Grid.Column="7" Text="{Binding Topic}"/>
                <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="8"
                           Text="{Binding ISBN}"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <ListBox Grid.Row="0"
                 ItemTemplate="{StaticResource LBXDataTemplate}"
                 ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 VirtualizingPanel.IsVirtualizing="True"
                 VirtualizingPanel.IsContainerVirtualizable="True"
                 VirtualizingPanel.VirtualizationMode="Recycling"
                 ScrollViewer.IsDeferredScrollingEnabled="True"/>

        <StackPanel Orientation="Horizontal" Grid.Row="1"
                VerticalAlignment="Top" HorizontalAlignment="Left">            
            <TextBlock Text="{Binding StatusMsg}"
                       HorizontalAlignment="Stretch"
                       Foreground="Blue"
                       FontSize="30"/>
        </StackPanel>
    </Grid>
</Window>

 

//App.xaml.cs

using CommunityToolkit.Mvvm.DependencyInjection;
using System.Configuration;
using System.Data;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var serviceProvider = IocConfiguration.ConfigureServices();
            Ioc.Default.ConfigureServices(serviceProvider);
        }
    }

}

 

 

 

//cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
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 System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    { 
        public MainWindow()
        {
            InitializeComponent();
            DataContext=Ioc.Default.GetService<MainVM>();
            this.SizeChanged+=MainWindow_SizeChanged;
        }

        private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
        {
             if(DataContext is MainVM vm && Content is FrameworkElement fe)
            {
                vm.GridWidth=fe.ActualWidth;
                vm.GridHeight=fe.ActualHeight/2;
            }
        }
    }  

    public partial class MainVM:ObservableObject
    {
        private readonly IBookService bookService;
        private CancellationTokenSource cancellationTokenSource;

        public MainVM(IBookService bookServiceValue)
        {
            bookService = bookServiceValue;
            //LoadDataCommand=new AsyncRelayCommand(LoadDataCommandExecutedAsync);
            //CancelCommand=new RelayCommand(CancelLoading);
            Task task = LoadDataCommandExecutedAsync();
        }

        private void CancelLoading()
        {
            cancellationTokenSource?.Cancel();
        }

        private async Task LoadDataCommandExecutedAsync()
        {
             if(IsLoading)
            {
                return;
            }

            IsLoading=true;
            StatusMsg="Loading data...";
            cancellationTokenSource=new CancellationTokenSource();
            try
            {
                var progress = new Progress<string>(x => StatusMsg=x);

                var books = await bookService.LoadBooksAsync(
                    100000,
                    progress,
                    cancellationTokenSource.Token);

                BooksCollection = books;
                StatusMsg=$"Loaded {BooksCollection.Count} items successfully!";
            }
            catch(OperationCanceledException ex)
            {
                StatusMsg="Loading cancelled!";
            }
            catch (Exception ex)
            {
                StatusMsg=$"Error:{ex.Message}";
            }
            finally
            {
                IsLoading=false;
                cancellationTokenSource?.Dispose();
                cancellationTokenSource=null;
            }
        }

        [ObservableProperty]
        private ObservableCollection<Book> booksCollection = new ObservableCollection<Book>();

        [ObservableProperty]
        private double gridWidth;

        [ObservableProperty]
        private double gridHeight;

        [ObservableProperty]
        private string statusMsg = "Ready to load data";

        [ObservableProperty]
        private bool isLoading;

        public IAsyncRelayCommand LoadDataCommand { get; }

        public ICommand CancelCommand { get; }
    }



    public static class IocConfiguration
    {
        public static IServiceProvider ConfigureServices()
        {
            var services = new ServiceCollection();
            services.AddTransient<MainVM>();
            services.AddTransient<IBookService, BookService>();
            services.AddSingleton<IImageService, ImageService>();
            return services.BuildServiceProvider();
        }
    }

    public class ImageService : IImageService
    {
        public ImageService() { }

        public ImageSource GetImgSourceViaUrl(string imgUrl)
        {
            BitmapImage bmi = new BitmapImage();
            if (!File.Exists(imgUrl))
            {
                return bmi;
            }

            bmi.BeginInit();
            bmi.UriSource=new Uri(imgUrl, UriKind.RelativeOrAbsolute);
            bmi.CacheOption=BitmapCacheOption.OnDemand;
            bmi.EndInit();
            if (bmi.CanFreeze)
            {
                bmi.Freeze();
            }
            return bmi;
        }
    }

    public interface IImageService
    {
        ImageSource GetImgSourceViaUrl(string imgUrl);
    }

    public interface IBookService
    {
        Task<ObservableCollection<Book>> LoadBooksAsync(int count, IProgress<string> progress,CancellationToken cancelToken);
    }

    public class BookService : IBookService
    {
        private readonly IImageService imgService;
        public BookService(IImageService imgServiceValue)
        {
            imgService = imgServiceValue;
        }

        public async Task<ObservableCollection<Book>> LoadBooksAsync(int count, IProgress<string> progress, CancellationToken cancellationToken)
        {
            var books=new ObservableCollection<Book>();
            var imgDir = @"../../../Images";
            if(!Directory.Exists(imgDir))
            {
                progress.Report("Images directly not found.");
                return books;
            }
            
            var imgs=Directory.GetFiles(imgDir);
            if(imgs.Length==0)
            {
                progress.Report("No images found in directory!");
                return books;
            }

            int imgsCount = imgs.Count();

            await Task.Run(() =>
            {
                for (int i = 1; i<count+1; i++)
                {
                    var book = new Book()
                    {
                        Id=i,
                        Name=$"Name_{i}",
                        Author=$"Author+{i}",
                        Comment=$"Comment_{i}",
                        Content=$"Content_{i}",
                        Summary=$"Summary_{i}",
                        Title=$"Title_{i}",
                        Topic=$"Topic_{i}",
                        ISBN=$"ISBN_{i}_{Guid.NewGuid():N}",
                        ImgSource=imgService.GetImgSourceViaUrl(imgs[i%imgsCount])
                    };
                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        books.Add(book);
                    });

                    if (i%10000==0)
                    {
                        progress.Report($"Loaded {i} items...");
                    }

                    if(cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                }
            });
            return books;
        }
    }

    

    public class Book
    {
        public int Id { get;set; }
        public string Name { 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 ISBN { get; set; }
        public ImageSource ImgSource { get; set; }
    }
}

 

image

 

posted @ 2025-09-12 16:54  FredGrit  阅读(7)  评论(0)    收藏  举报