通過改變ListView控件的ItemsControl.ItemContainerStyle樣式可以實作各式各樣的清單展示效果。如果背景讀取檔案夾圖檔資源後最後給ListView的ItemsSource指派,可以在前台顯示加載的圖檔清單,但是由于加載圖檔需要時間,會有一段空白停頓,并且要加載的圖檔越大停頓的時間越長。如下圖所示:
這裡的解決方案是首先異步加載圖檔位址,再異步讀取圖檔資源的方式來加載本地圖檔清單。效果如下:
具體代碼:
1、自定義控件ucListPicView.xaml
<ListView x:Class="ListViewDemo.ucListPicView"
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:ListViewDemo"
mc:Ignorable="d" SelectionMode="Single" Background="#f0f0f0"
ItemContainerStyle="{DynamicResource ListViewItemStyle}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.Resources>
<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="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>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Border Name="picBorder" Background="White" BorderBrush="DarkGray" BorderThickness="1">
<Image Name="ItemPic" Width="{Binding ItemWidth}" Height="{Binding ItemHeight}" Source="{Binding ItemPic}" Stretch="{Binding StrethMethod}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<ContentControl Name="ItemName" Content="{Binding ItemName}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Margin="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="picBorder" Property="BorderBrush" Value="DarkBlue"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="picBorder" Property="BorderBrush" Value="Blue"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel>
</WrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
2、自定義控件背景代碼ucListPicView.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace ListViewDemo
{
/// <summary>
/// ucListPicView.xaml 的互動邏輯
/// </summary>
public partial class ucListPicView : ListView
{
private BackgroundWorker loadLocalBackgroudworker = null;//背景處理線程
private ObservableCollection<ListBindData> bindItems = null;// 綁定的資源元素集合
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 ucListPicView()
{
InitializeComponent();
bindItems = new ObservableCollection<ListBindData>();
}
#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.ItemPath = 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.ItemPath))
{
BitmapImage bi = LoadBitmapSourceByPath(tempData.ItemPath);
if (bi != null)
{
tempData.ItemPic = 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 輔助方法
/// <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
}
public class ListBindData : INotifyPropertyChanged
{
public ListBindData()
{
}
private ImageSource itemPic;
private Stretch strethmethod = Stretch.Uniform;
/// <summary>
/// 素材展示預覽圖
/// </summary>
public ImageSource ItemPic
{
get
{
return itemPic;
}
set
{
if (itemPic != value)
{
itemPic = value;
OnPropertyChanged("ItemPic");
}
}
}
public Stretch StrethMethod
{
get
{
return strethmethod;
}
set
{
if (strethmethod != value)
{
strethmethod = value;
OnPropertyChanged("StrethMethod");
}
}
}
/// <summary>
/// 圖檔名稱
/// </summary>
public string ItemName
{
get;
set;
}
/// <summary>
/// 圖檔的本地路徑
/// </summary>
public string ItemPath
{
get;
set;
}
/// <summary>
/// 圖檔的寬
/// </summary>
public int ItemWidth
{
get;
set;
}
/// <summary>
/// 圖檔的高
/// </summary>
public int ItemHeight
{
get;
set;
}
private void OnPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
3、主窗體MainWindow.xaml
<Window x:Class="ListViewDemo.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:ListViewDemo"
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="450" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<local:ucListPicView x:Name="picListView" Width="180" Margin="10"></local:ucListPicView>
<Button x:Name="btnOpenFile" Content="打開" Grid.Row="1" Width="100" Margin="10,0,10,10" Click="btnOpenFile_Click"></Button>
</Grid>
</Window>
4、主窗體背景代碼
using System;
using System.Windows;
using System.Windows.Forms;
namespace ListViewDemo
{
/// <summary>
/// MainWindow.xaml 的互動邏輯
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnOpenFile_Click(object sender, RoutedEventArgs e)
{
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
folderBrowserDialog.Description = "選擇圖檔所在的檔案夾";
folderBrowserDialog.ShowNewFolderButton = false;
folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer;//設定目錄,可注掉
folderBrowserDialog.ShowDialog();
if (folderBrowserDialog.SelectedPath == string.Empty)
{
return;
}
string selectFolder = folderBrowserDialog.SelectedPath;
this.picListView.NameLargeLength = 20;
this.picListView.ItemSourcePath = selectFolder;
}
}
}