付出与汲取

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="&#xed1b;"/>
            <!--触发器,控制文字(矢量图标)及文字颜色-->
            <Style.Triggers>
                <Trigger Property="Tag" Value="1">
                    <Setter Property="Foreground" Value="#FFFF33"/>
                    <Setter Property="Text" Value="&#xe8b1;"/>
                </Trigger>
                <Trigger Property="Tag" Value="0">
                    <Setter Property="Text" Value="&#xed1b;"/>
                    <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

posted on 2022-06-02 11:14  付出与汲取  阅读(1445)  评论(0编辑  收藏  举报

导航