WPF ItemsControl IsItemsHost=True

 <ItemsControl ItemsSource="{Binding BooksCollection}">
     <ItemsControl.Template>
         <ControlTemplate TargetType="ItemsControl">
             <DockPanel LastChildFill="True">
                 <TextBlock Text="IsItemsHost=True" FontSize="50" 
                            DockPanel.Dock="Top"/>
                 <ScrollViewer CanContentScroll="True">
                     <VirtualizingStackPanel IsItemsHost="True"
                              VirtualizingPanel.IsVirtualizing="True"
                              VirtualizingPanel.VirtualizationMode="Recycling"
                              ScrollViewer.CanContentScroll="True"
                              ScrollViewer.IsDeferredScrollingEnabled="True"                                                        
                              VirtualizingPanel.CacheLength="2,2"
                              VirtualizingPanel.CacheLengthUnit="Item">
                     </VirtualizingStackPanel>
                 </ScrollViewer>
             </DockPanel>
         </ControlTemplate>
     </ItemsControl.Template>
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <Grid Margin="5" Width="{x:Static SystemParameters.FullPrimaryScreenWidth}" 
                   Height="{x:Static SystemParameters.FullPrimaryScreenHeight}">
                 <Grid.RowDefinitions>
                     <RowDefinition/>
                     <RowDefinition/>
                 </Grid.RowDefinitions>
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                 </Grid.ColumnDefinitions>
                 <Grid.Resources>
                     <Style TargetType="TextBlock">
                         <Setter Property="FontSize" Value="30"/>
                         <Style.Triggers>
                             <Trigger Property="IsMouseOver" Value="True">
                                 <Setter Property="FontSize" Value="50"/>
                                 <Setter Property="Foreground" Value="Red"/>
                             </Trigger>
                         </Style.Triggers>
                     </Style>
                 </Grid.Resources>
                 <Image Source="{Binding ImgUrl,Converter={StaticResource ImgConverter}}"
                            Stretch="Uniform"
                            Grid.Row="0"
                            Grid.RowSpan="2"
                            Grid.Column="0"
                            Grid.ColumnSpan="2"/>
                 <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="1" Grid.Column="0" Grid.ColumnSpan="2"/>
             </Grid>
         </DataTemplate>
     </ItemsControl.ItemTemplate>
 </ItemsControl>

 

image

 

<Window x:Class="WpfApp12.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:WpfApp12"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="{Binding MainTitle}">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <local:ImgConverter x:Key="ImgConverter"/>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding BooksCollection}">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <DockPanel LastChildFill="True">
                        <TextBlock Text="IsItemsHost=True" FontSize="50" 
                                   DockPanel.Dock="Top"/>
                        <ScrollViewer CanContentScroll="True">
                            <VirtualizingStackPanel IsItemsHost="True"
                                     VirtualizingPanel.IsVirtualizing="True"
                                     VirtualizingPanel.VirtualizationMode="Recycling"
                                     ScrollViewer.CanContentScroll="True"
                                     ScrollViewer.IsDeferredScrollingEnabled="True"                                                        
                                     VirtualizingPanel.CacheLength="2,2"
                                     VirtualizingPanel.CacheLengthUnit="Item">
                            </VirtualizingStackPanel>
                        </ScrollViewer>
                    </DockPanel>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="5" Width="{x:Static SystemParameters.FullPrimaryScreenWidth}" 
                          Height="{x:Static SystemParameters.FullPrimaryScreenHeight}">
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <Grid.Resources>
                            <Style TargetType="TextBlock">
                                <Setter Property="FontSize" Value="30"/>
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="FontSize" Value="50"/>
                                        <Setter Property="Foreground" Value="Red"/>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Grid.Resources>
                        <Image Source="{Binding ImgUrl,Converter={StaticResource ImgConverter}}"
                                   Stretch="Uniform"
                                   Grid.Row="0"
                                   Grid.RowSpan="2"
                                   Grid.Column="0"
                                   Grid.ColumnSpan="2"/>
                        <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="1" Grid.Column="0" Grid.ColumnSpan="2"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>


using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
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 WpfApp12
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private DateTime startTime;
        public MainVM()
        {
            Task.Run(async () =>
            {
                await InitBooksCollection(52600000);
            });
        }
        public async Task InitBooksCollection(int cnt = 100000)
        {
            BooksCollection = new ObservableCollection<Book>();
            List<Book> booksList = new List<Book>();
            var imgDir = @"../../../Images";
            if (!Directory.Exists(imgDir))
            {
                return;
            }
            var imgs = Directory.GetFiles(imgDir);
            if (imgs == null || !imgs.Any())
            {
                return;
            }
            int imgsCount = imgs.Count();

            startTime = DateTime.Now;
            for (int i = 1; i < cnt + 1; i++)
            {
                booksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    ImgUrl = $"{imgs[i % imgsCount]}"
                });

                if (i < 1000 && i % 200 == 0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                    await Task.Delay(1);
                }

                else if (i % 1000000 == 0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                    await Task.Delay(1);
                }
            }

            if (booksList.Any())
            {
                await PopulateBooksCollectionAsync(booksList);
            }
        }

        private async Task PopulateBooksCollectionAsync(List<Book> booksList)
        {
            var tempList = booksList.ToList();
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                foreach (var bk in tempList)
                {
                    BooksCollection.Add(bk);
                }
                MainTitle = $"{DateTime.Now},loaded {BooksCollection.Count} items,{GetMem()},{GetTimeCost()}";
                booksList.Clear();
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        public string GetTimeCost()
        {
            var dtSpan = DateTime.Now.Subtract(startTime);
            return $"Time cost {dtSpan.TotalSeconds:0.00} seconds";
        }

        private string GetMem()
        {
            return $"{System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024:N2} M";
        }

        private string mainTitle = "";
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                if (value != mainTitle)
                {
                    mainTitle = value;
                    OnPropertyChanged();
                }
            }
        }

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

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class ImgConverter : IValueConverter
    {
        private Dictionary<string, ImageSource> imgCache = new Dictionary<string, ImageSource>();
        private readonly object objLock = new object();
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var imgUrl = value?.ToString();
            if (string.IsNullOrWhiteSpace(imgUrl) || !File.Exists(imgUrl))
            {
                return null;
            }

            lock (objLock)
            {
                if (imgCache.ContainsKey(imgUrl))
                {
                    return imgCache[imgUrl];
                }

                BitmapImage bmi = new BitmapImage();
                bmi.BeginInit();
                bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute);
                //bmi.DecodePixelWidth = 1200;
                //bmi.DecodePixelHeight = 700;
                bmi.CacheOption = BitmapCacheOption.OnLoad;
                bmi.EndInit();
                if (bmi.CanFreeze)
                {
                    bmi.Freeze();
                }
                imgCache[imgUrl] = bmi;
                return bmi;
            }
            return null;
        }


        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }
    }


    public class DelCommand : ICommand
    {
        private Action<object?>? execute;
        private Predicate<object?>? canExecute;
        public DelCommand(Action<object?>? executeValue, Predicate<object?>? canExecuteValue = null)
        {
            execute = executeValue;
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute?.Invoke(parameter);
        }
    }


    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string ImgUrl { get; set; }
    }

}

image

 

 

 

 <ItemsControl ItemsSource="{Binding BooksCollection}">
     <ItemsControl.Template>
         <ControlTemplate TargetType="ItemsControl">
             <ScrollViewer CanContentScroll="True">
                 <VirtualizingStackPanel IsItemsHost="True"
                              VirtualizingPanel.IsVirtualizing="True"
                              VirtualizingPanel.VirtualizationMode="Recycling"
                              ScrollViewer.CanContentScroll="True"
                              ScrollViewer.IsDeferredScrollingEnabled="True"                                                        
                              VirtualizingPanel.CacheLength="2,2"
                              VirtualizingPanel.CacheLengthUnit="Item"/> 
             </ScrollViewer>
         </ControlTemplate>
     </ItemsControl.Template>
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <Grid Margin="5" Width="{x:Static SystemParameters.FullPrimaryScreenWidth}" 
                   Height="{x:Static SystemParameters.FullPrimaryScreenHeight}">
                 <Grid.RowDefinitions>
                     <RowDefinition/>
                     <RowDefinition/>
                 </Grid.RowDefinitions>
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition/>
                     <ColumnDefinition/>
                 </Grid.ColumnDefinitions>
                 <Grid.Resources>
                     <Style TargetType="TextBlock">
                         <Setter Property="FontSize" Value="30"/>
                         <Style.Triggers>
                             <Trigger Property="IsMouseOver" Value="True">
                                 <Setter Property="FontSize" Value="50"/>
                                 <Setter Property="Foreground" Value="Red"/>
                             </Trigger>
                         </Style.Triggers>
                     </Style>
                 </Grid.Resources>
                 <Image Source="{Binding ImgUrl,Converter={StaticResource ImgConverter}}"
                            Stretch="Uniform"
                            Grid.Row="0"
                            Grid.RowSpan="2"
                            Grid.Column="0"
                            Grid.ColumnSpan="2"/>
                 <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="1" Grid.Column="0" Grid.ColumnSpan="2"/>
             </Grid>
         </DataTemplate>
     </ItemsControl.ItemTemplate>
 </ItemsControl>

 

<Window x:Class="WpfApp12.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:WpfApp12"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="{Binding MainTitle}">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <local:ImgConverter x:Key="ImgConverter"/>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding BooksCollection}">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <ScrollViewer CanContentScroll="True">
                        <VirtualizingStackPanel IsItemsHost="True"
                                     VirtualizingPanel.IsVirtualizing="True"
                                     VirtualizingPanel.VirtualizationMode="Recycling"
                                     ScrollViewer.CanContentScroll="True"
                                     ScrollViewer.IsDeferredScrollingEnabled="True"                                                        
                                     VirtualizingPanel.CacheLength="2,2"
                                     VirtualizingPanel.CacheLengthUnit="Item"/> 
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="5" Width="{x:Static SystemParameters.FullPrimaryScreenWidth}" 
                          Height="{x:Static SystemParameters.FullPrimaryScreenHeight}">
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <Grid.Resources>
                            <Style TargetType="TextBlock">
                                <Setter Property="FontSize" Value="30"/>
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="FontSize" Value="50"/>
                                        <Setter Property="Foreground" Value="Red"/>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Grid.Resources>
                        <Image Source="{Binding ImgUrl,Converter={StaticResource ImgConverter}}"
                                   Stretch="Uniform"
                                   Grid.Row="0"
                                   Grid.RowSpan="2"
                                   Grid.Column="0"
                                   Grid.ColumnSpan="2"/>
                        <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="1" Grid.Column="0" Grid.ColumnSpan="2"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
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 WpfApp12
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private DateTime startTime;
        public MainVM()
        {
            Task.Run(async () =>
            {
                await InitBooksCollection(52600000);
            });
        }
        public async Task InitBooksCollection(int cnt = 100000)
        {
            BooksCollection = new ObservableCollection<Book>();
            List<Book> booksList = new List<Book>();
            var imgDir = @"../../../Images";
            if (!Directory.Exists(imgDir))
            {
                return;
            }
            var imgs = Directory.GetFiles(imgDir);
            if (imgs == null || !imgs.Any())
            {
                return;
            }
            int imgsCount = imgs.Count();

            startTime = DateTime.Now;
            for (int i = 1; i < cnt + 1; i++)
            {
                booksList.Add(new Book()
                {
                    Id = i,
                    Name = $"Name_{i}",
                    ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
                    ImgUrl = $"{imgs[i % imgsCount]}"
                });

                if (i < 1000 && i % 200 == 0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                    await Task.Delay(1);
                }

                else if (i % 1000000 == 0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                    await Task.Delay(1);
                }
            }

            if (booksList.Any())
            {
                await PopulateBooksCollectionAsync(booksList);
            }
        }

        private async Task PopulateBooksCollectionAsync(List<Book> booksList)
        {
            var tempList = booksList.ToList();
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                foreach (var bk in tempList)
                {
                    BooksCollection.Add(bk);
                }
                MainTitle = $"{DateTime.Now},loaded {BooksCollection.Count} items,{GetMem()},{GetTimeCost()}";
                booksList.Clear();
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        public string GetTimeCost()
        {
            var dtSpan = DateTime.Now.Subtract(startTime);
            return $"Time cost {dtSpan.TotalSeconds:0.00} seconds";
        }

        private string GetMem()
        {
            return $"{System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024:N2} M";
        }

        private string mainTitle = "";
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                if (value != mainTitle)
                {
                    mainTitle = value;
                    OnPropertyChanged();
                }
            }
        }

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

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class ImgConverter : IValueConverter
    {
        private Dictionary<string, ImageSource> imgCache = new Dictionary<string, ImageSource>();
        private readonly object objLock = new object();
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var imgUrl = value?.ToString();
            if (string.IsNullOrWhiteSpace(imgUrl) || !File.Exists(imgUrl))
            {
                return null;
            }

            lock (objLock)
            {
                if (imgCache.ContainsKey(imgUrl))
                {
                    return imgCache[imgUrl];
                }

                BitmapImage bmi = new BitmapImage();
                bmi.BeginInit();
                bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute);
                //bmi.DecodePixelWidth = 1200;
                //bmi.DecodePixelHeight = 700;
                bmi.CacheOption = BitmapCacheOption.OnLoad;
                bmi.EndInit();
                if (bmi.CanFreeze)
                {
                    bmi.Freeze();
                }
                imgCache[imgUrl] = bmi;
                return bmi;
            }
            return null;
        }


        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }
    }


    public class DelCommand : ICommand
    {
        private Action<object?>? execute;
        private Predicate<object?>? canExecute;
        public DelCommand(Action<object?>? executeValue, Predicate<object?>? canExecuteValue = null)
        {
            execute = executeValue;
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute?.Invoke(parameter);
        }
    }


    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string ImgUrl { get; set; }
    }

}

image

 

image

 

image

 

posted @ 2026-04-07 21:21  FredGrit  阅读(5)  评论(0)    收藏  举报