WPF加载大量的图片显示

一、问题

如何在WPF中加载大批量数据,并且不会阻塞UI线程,尤其是加载大量图片时?

二、方案

大致情况是:数据源集合是一个 ObservableCollection<PictureInfo>, 也就是说集合中放的是图像的一个自定义类,包含了Info,PicturePath等属性。界面通过Bind,使用转换器,将路径转换为ImageSource对象即可。不要直接加载ImageSource

PictureInfo:图像信息类

  /// <summary>
    /// 图片信息类
    /// </summary>
    public class PictureInfo 
    {
        
        /// <summary>
        /// 图片信息
        /// </summary>
        public string Info { get; set; }

        /// <summary>
        /// 图片路径
        /// </summary>
        public string PicturePath { get; set; }

     

       
    }

为什么不放BitmapSource属性 呢,因为 DependencyObject 是不能跨线程操作的,只能在UI线程上创建。默认情况下,ObservableCollection<T>也不能在非UI线程上操作,不过,我可以通过调用以下方法来让它可以跨线程操作:

public static void EnableCollectionSynchronization(IEnumerable collection, object lockObject)

这个方法是 BindingOperations 类公开的静态方法,可以在窗口的构造函数中调用它,而且一定要在操作集合之前调用。调用时,把 ObservableCollection 集合传递给 collection 参数,第二个参数lockObject 是一个自定义对象,它指的是可以在线程间同步时引用的对象,

三、实例

 XAML

 <ListBox x:Name="imagListBox"
                  VirtualizingStackPanel.IsVirtualizing="True" 
                      ItemContainerStyle="{StaticResource ImageItemStyle}"
                      ItemsSource="{Binding ImageList, Mode=OneWay,IsAsync=True}"
                      BorderBrush="#eaeaeb" 
                      Margin="5"/>

  <Style x:Key="ImageItemStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border x:Name="Part_Border" 
                            Width="{TemplateBinding ListBoxItem.Width}"
                            Height="{TemplateBinding ListBoxItem.Height}"
                            Background="{TemplateBinding ListBoxItem.Background}">
                        <Grid x:Name="Part_Grid" Margin="2">
                            <Image Grid.Row="1"
                                   Width="240"
                                   Height="180"
                                   Stretch="Uniform"
                                   Source="{Binding PicturePath,IsAsync=True,Converter={StaticResource PathToImage},Mode=OneWay}"></Image>
                        </Grid>
                    </Border>


                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

转换器

  public sealed class PathToImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
            {
                return null;
            }
            string uriStr = (string)value;
            Uri uri = new Uri(uriStr, UriKind.Absolute);
            BitmapImage bmp = new BitmapImage();
            bmp.DecodePixelHeight = 250; // 确定解码高度,宽度不同时设置
            bmp.BeginInit();
            // 延迟,必要时创建
            bmp.CreateOptions = BitmapCreateOptions.DelayCreation;
            bmp.CacheOption = BitmapCacheOption.OnLoad;
            bmp.UriSource = uri;
            bmp.EndInit(); //结束初始化
            return bmp;
        }

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

       
    }

c# 后台

  private ObservableCollection<PictureInfo> imageList = new ObservableCollection<PictureInfo>();
        public ObservableCollection<PictureInfo> ImageList
        {
            get { return imageList; }
            set
            {
                NotifyChanged("ImageList");
                imageList = value;
            }
        }

  
object lockobj = new object();

        /// <summary>
        /// 加载缺陷图片
        /// </summary>
        /// <param name="strPath"></param>
        public void LoadPicture(string strPath)
        {
            ImageList.Clear();

            BindingOperations.EnableCollectionSynchronization(ImageList, lockobj);

            string folderFullName = strPath ;//图片文件夹路径

            Task.Run(() =>
            {
                DirectoryInfo TheFolder = new DirectoryInfo(folderFullName);
                var res = TheFolder.GetFiles();

                for (int i = 0; i < res.Length; i++)
                {
                    PictureInfo pictureInfo = new PictureInfo();
                    pictureInfo.PicturePath = res[i].DirectoryName + @"\" + res[i].Name;
                    Uri uri = new Uri(pictureInfo.PicturePath, UriKind.Absolute);
                    BitmapImage myimg = ImageProcess.GetBitImage(uri);
                    pictureInfo.Info = res[i].Name;
                    ImageList.Add(pictureInfo);
                }

            });
        }

参考:

https://www.cnblogs.com/tcjiaan/p/5532104.html

https://www.jb51.net/article/36749.htm

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107255094
今日推荐