WPF中,使用LISTVIEW显示图片列表,含异步显示方法
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; 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.Windows.Threading; namespace LibraryControls { /// <summary> /// ImageListView.xaml 的交互逻辑 /// </summary> public partial class ImageListView_M : ListView { private BackgroundWorker loadLocalBackgroudworker = null;//后台处理线程 public ObservableCollection<ListBindData> bindItems = null;// 绑定的资源元素集合 #region Event public delegate void Image_LoadDelegate(ListBindData model); /// <summary> ///图片加载事件 /// </summary> public event Image_LoadDelegate Image_LoadEvent; public delegate void Image_MouseDownDelegate(object sender, MouseButtonEventArgs e); /// <summary> /// 鼠标在图片上按下事件 /// </summary> public event Image_MouseDownDelegate Image_MouseDownEvent; public delegate void Image_MouseMoveDelegate(object sender, MouseEventArgs e); /// <summary> /// 鼠标在图片上移动事件 /// </summary> public event Image_MouseMoveDelegate Image_MouseMoveEvent; public delegate void Image_MouseUpDelegate(object sender, MouseButtonEventArgs e); /// <summary> /// 鼠标在图片上松开事件 /// </summary> public event Image_MouseUpDelegate Image_MouseUpEvent; #endregion private int nameLargeLength;//可展示的图片名称字数 public int NameLargeLength { get { return nameLargeLength; } set { nameLargeLength = value; } } private string itemSourcePath;//图片路径 public string ItemSourcePath { get { return itemSourcePath; } set { itemSourcePath = value; LoadLocalImageData(); } } public ImageListView_M() { InitializeComponent(); //bindItems = new ObservableCollection<ListBindData>(); //this.ItemsSource = bindItems; } #region 后台线程处理图片数据 private void LoadLocalImageData() { this.ItemsSource = null; bindItems.Clear(); if (loadLocalBackgroudworker != null) { loadLocalBackgroudworker.CancelAsync(); loadLocalBackgroudworker.DoWork -= loadLocalBackgroudworker_DoWork; loadLocalBackgroudworker.RunWorkerCompleted -= loadLocalBackgroudworker_RunWorkerCompleted; } loadLocalBackgroudworker = new BackgroundWorker(); loadLocalBackgroudworker.WorkerSupportsCancellation = true; loadLocalBackgroudworker.DoWork += loadLocalBackgroudworker_DoWork; loadLocalBackgroudworker.RunWorkerCompleted += loadLocalBackgroudworker_RunWorkerCompleted; loadLocalBackgroudworker.RunWorkerAsync(); } /// <summary> /// 逐个加载图片资源 /// </summary> private void loadLocalBackgroudworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { this.ItemsSource = bindItems; int tempCount = bindItems.Count; for (int i = 0; i < bindItems.Count; i++) { if (tempCount != bindItems.Count) { break; } LoadImageDataByBackground(bindItems[i]); } } /// <summary> /// 加载资源路径 /// </summary> private void loadLocalBackgroudworker_DoWork(object sender, DoWorkEventArgs e) { try { DirectoryInfo theFolder = new DirectoryInfo(ItemSourcePath); if (!theFolder.Exists) return; string[] files = Directory.GetFiles(ItemSourcePath); if (files.Length > 0) Array.Sort(files); for (int i = 0; i < files.Length; i++) { this.Dispatcher.Invoke(new Action(() => { if (IsSupport(files[i])) { var tmpBindData = new ListBindData(); tmpBindData.ItemName = SetStringLength(GetFileNameEx(files[i]), nameLargeLength); tmpBindData.PicPath = files[i]; tmpBindData.ItemWidth = 160; tmpBindData.ItemHeight = 80; bindItems.Add(tmpBindData); } })); } } catch (Exception ex) { } } /// <summary> /// 加载资源图片线程 /// </summary> private void LoadImageDataByBackground(ListBindData bindData) { BackgroundWorker loadImgWorker = new BackgroundWorker(); loadImgWorker.DoWork += loadImgWorker_DoWork; loadImgWorker.RunWorkerCompleted += loadImgWorker_RunWorkerCompleted; loadImgWorker.WorkerSupportsCancellation = true; loadImgWorker.RunWorkerAsync(bindData); } /// <summary> /// 后台线程完成后释放所占资源 /// </summary> private void loadImgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { var tempWorker = sender as BackgroundWorker; if (tempWorker != null) { tempWorker.Dispose(); tempWorker = null; } } /// <summary> /// 更新资源图片 /// </summary> private void loadImgWorker_DoWork(object sender, DoWorkEventArgs e) { var bindData = e.Argument as ListBindData; if (bindData != null) { var temp = this.Dispatcher.BeginInvoke(new Action<ListBindData>((tempData) => { if (tempData != null && !string.IsNullOrEmpty(tempData.PicPath)) { BitmapImage bi = LoadBitmapSourceByPath(tempData.PicPath); if (bi != null) { tempData.PicBitmapImage = bi; if (bi.PixelWidth < tempData.ItemWidth && bi.PixelHeight < tempData.ItemHeight) { tempData.StrethMethod = Stretch.None; } else { tempData.StrethMethod = Stretch.UniformToFill; } } bi = null; } }), DispatcherPriority.Background, bindData); } } #endregion #region 异步加载图片资源(解决BitmapImage无法异步加载的问题) /// <summary> /// 异步加载图片资源 /// </summary> /// <param name="model"></param> public void LoadBitmapImageAsync(ListBindData model) { BackgroundWorker loadImgWorker = new BackgroundWorker(); loadImgWorker.DoWork += LoadBitmapImage_DoWork; loadImgWorker.RunWorkerCompleted += loadImgWorker_RunWorkerCompleted; loadImgWorker.WorkerSupportsCancellation = true; loadImgWorker.RunWorkerAsync(model); } /// <summary> /// 更新资源图片 /// </summary> private void LoadBitmapImage_DoWork(object sender, DoWorkEventArgs e) { var bindData = e.Argument as ListBindData; if (bindData != null) { var temp = this.Dispatcher.BeginInvoke(new Action<ListBindData>((tempData) => { if (Image_LoadEvent != null) {
//根据需要,将图片的PICPATH(图片路径),转换成bitmapimage类型,由于这里有特殊需求,所以用事件代替执行 Image_LoadEvent(tempData); } }), DispatcherPriority.Background, bindData); } } #endregion #region 辅助方法 /// <summary> /// 设置显示的图片名称 /// </summary> private string SetStringLength(string text, int leng) { if (text.Length > leng) { text = text.Substring(0, leng) + "..."; return text; } else { return text; } } /// <summary> /// 从文件路径中获取文件名 /// </summary> private static String GetFileName(String fileName) { if (fileName == null || fileName == "") return ""; return fileName.Substring(fileName.LastIndexOf("\\") + 1); } /// <summary> /// 获得文件后缀名 /// </summary> private static String GetEndFile(String fileName) { return fileName.Substring(fileName.LastIndexOf(".") + 1); } /// <summary> /// 获得没有后缀的文件名 /// </summary> private static string GetFileNameEx(String fileName) { try { return GetFileName(fileName).Substring(0, GetFileName(fileName).LastIndexOf(GetEndFile(fileName)) - 1); } catch { return ""; } } /// <summary> /// 文件头转换 /// </summary> private enum FileExtension { JPG = 255216, GIF = 7173, PNG = 13780, SWF = 6787, RAR = 8297, ZIP = 8075, _7Z = 55122, VALIDFILE = 9999999 } /// <summary> /// 根据图源属性获取扩展名 /// </summary> private string GetBitmapExtensions(string path) { try { using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { string fileType = string.Empty; FileExtension extension; using (BinaryReader br = new System.IO.BinaryReader(fs)) { byte data = br.ReadByte(); fileType += data.ToString(); data = br.ReadByte(); fileType += data.ToString(); try { extension = (FileExtension)Enum.Parse(typeof(FileExtension), fileType); } catch { extension = FileExtension.VALIDFILE; } } return extension.ToString(); } } catch (Exception) { return FileExtension.VALIDFILE.ToString(); } } /// <summary> /// 受支持的图片格式 /// </summary> private List<string> supportedPicType = new List<string>() { "jpg", "png", "bmp", }; /// <summary> /// 判断该扩展名是否是受支持的图片类型 /// </summary> private bool IsBmpSupport(string ext) { return supportedPicType.FindAll((c) => c.Contains(ext.ToLower())).Count > 0; } /// <summary> /// 判断该图片是否受支持 /// </summary> private bool IsSupport(string path) { return IsBmpSupport(GetBitmapExtensions(path)); } /// <summary> /// 从指定路径读取图片源 /// </summary> private BitmapImage LoadBitmapSourceByPath(string path) { try { //文件不存在,返回空 if (!File.Exists(path)) { return null; } BitmapImage bi = new BitmapImage(); using (FileStream strream = new FileStream(path, FileMode.Open, FileAccess.Read)) { using (BinaryReader br = new BinaryReader(strream)) { byte[] bytes = br.ReadBytes((int)strream.Length); bi.BeginInit(); bi.StreamSource = new MemoryStream(bytes); bi.EndInit(); } } return bi; } catch (Exception ex) { return null; } } #endregion #region Method /// <summary> /// 添加项 /// </summary> /// <param name="item"></param> public void AddItem(ListBindData item) { try { this.Dispatcher.Invoke(new Action(() => { bindItems.Add(item); })); LoadBitmapImageAsync(item); } catch (Exception ex) { } } /// <summary> /// 定位到指定位置 /// </summary> /// <param name="item"></param> public void Location(ListBindData item) { try { //信息定位到最底部 this.ScrollIntoView(item); } catch (Exception ex) { } } /// <summary> /// 绑定数据源 /// </summary> public void SetItemSource() { this.ItemsSource = bindItems; } #endregion #region 事件 private void Image_MouseDown(object sender, MouseButtonEventArgs e) { if (Image_MouseDownEvent != null) { Image_MouseDownEvent(sender, e); } } private void Image_MouseMove(object sender, MouseEventArgs e) { if (Image_MouseMoveEvent != null) { Image_MouseMoveEvent(sender, e); } } private void Image_MouseUp(object sender, MouseButtonEventArgs e) { if (Image_MouseUpEvent != null) { Image_MouseUpEvent(sender, e); } } #endregion } }
前端代码:
<ListView x:Class="LibraryControls.ImageListView_M" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:LibraryControls" mc:Ignorable="d" SelectionMode="Single" Background="#f0f0f0" ItemContainerStyle="{DynamicResource ListViewItemStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto"> <ListView.Resources> <Style x:Key="txt_bottom" TargetType="TextBlock"> <!--矢量图标必须要写在这里,才可以用触发器改变图标,否则改变无效--> <Setter Property="FontFamily" Value="/Fonts/#iconfont" /> <Setter Property="Text" Value=""/> <!--触发器,控制文字(矢量图标)及文字颜色--> <Style.Triggers> <Trigger Property="Tag" Value="1"> <Setter Property="Foreground" Value="#FFFF33"/> <Setter Property="Text" Value=""/> </Trigger> <Trigger Property="Tag" Value="0"> <Setter Property="Text" Value=""/> <Setter Property="Foreground" Value="#00FF00"/> </Trigger> </Style.Triggers> </Style> <Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}"> <Setter Property="AllowDrop" Value="True"/> <!--<Setter Property="Cursor" Value ="Hand"/>--> <!--<Setter Property="Margin" Value="5,5,5,5"/>--> <Setter Property="Foreground" Value="Black"/> <Setter Property="Background" Value="Black"/> <Setter Property="FontSize" Value="12"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListViewItem}"> <Grid x:Name="gridContent" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="30"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <!--图片边框,不要边框可以设置为0--> <Border Name="picBorder" Background="White" BorderBrush="DarkGray" BorderThickness="3" Grid.ColumnSpan="2" Grid.RowSpan="2"> <!--<Image Name="ItemPic" Height="{Binding PicBitmapImage}" Source="{Binding PicBitmapImage}" Stretch="{Binding StrethMethod}" VerticalAlignment="Center" HorizontalAlignment="Center"/>--> <Image Name="ItemPic" Height="{Binding ItemHeight}" Source="{Binding PicBitmapImage}" Stretch="{Binding StrethMethod}" VerticalAlignment="Center" HorizontalAlignment="Center" Tag="{Binding Index}" MouseDown="Image_MouseDown" MouseMove="Image_MouseMove" MouseUp="Image_MouseUp"/> </Border> <TextBlock Grid.Row="1" FontSize="30" VerticalAlignment="Bottom" HorizontalAlignment="Left" Tag="{Binding IsDisease}" Style="{StaticResource txt_bottom}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="picBorder" Property="BorderBrush" Value="Blue"></Setter> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="picBorder" Property="BorderBrush" Value="Red"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListView.Resources> <ListView.ItemsPanel> <ItemsPanelTemplate> <WrapPanel> </WrapPanel> </ItemsPanelTemplate> </ListView.ItemsPanel> </ListView>
注意事项:如果在前端代码中,imageSoruce绑定的是图片路径,则后台添加项方法(AddItem)无需使用LoadBitmapImageAsync方法;在使用异步加载listview的时候,请实现Image_LoadEvent事件,或者直接在调用Image_LoadEvent事件处理,写相关代码即可。
参考文献:https://blog.csdn.net/weixin_43976890/article/details/99850570