
接續上次的程式,稍微改動一下原有樣式,并添加一個資料模闆,我們就可以達成下面這樣的顯示功能:
滑鼠懸停于檔案清單項上,會在工具提示中顯示圖像縮略圖及檔案名、檔案大小資訊。
選中一個清單項,該清單項會擴大,并動态顯示出一個小縮略圖及檔案的所在路徑。
代碼如下:
Code
<Application x:Class="自定義清單項.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:System.IO;assembly=mscorlib"
StartupUri="Window1.xaml">
<Application.Resources>
<!--FileInfo資料模闆-->
<DataTemplate DataType="{x:Type c:FileInfo}">
<WrapPanel VerticalAlignment="Center">
<WrapPanel.ToolTip>
<WrapPanel Width="164">
<Image Margin="2,4" MaxHeight="160" MaxWidth="160" Source="{Binding FullName}"/>
<TextBlock Text="{Binding Name}" Width="160" Margin="2"/>
<TextBlock Margin="2" Text="{Binding Length}"/><TextBlock Margin="2">位元組</TextBlock>
</WrapPanel>
</WrapPanel.ToolTip>
<Image x:Name="pic" Margin="2" Opacity="0" MaxHeight="0" MaxWidth="0" Source="{Binding FullName}" />
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="title" Height="24" Margin="2,0" Text="{Binding Name}"/>
<TextBlock x:Name="path" Opacity="0" Height="0" Margin="2,0" Text="{Binding FullName}"/>
</StackPanel>
</WrapPanel>
<DataTemplate.Triggers>
<Trigger Property="Height" Value="68">
<Setter TargetName="path" Property="Height" Value="24"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" BeginTime="0:0:0.1" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="Opacity" />
<DoubleAnimation To="64" BeginTime="0:0:0.1" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="MaxHeight" />
<DoubleAnimation To="64" BeginTime="0:0:0.1" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="MaxWidth" />
<DoubleAnimation To="0.4" BeginTime="0:0:0.1" Duration="0:0:0.1" Storyboard.TargetName="path" Storyboard.TargetProperty="Opacity" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<DoubleAnimation BeginTime="0:0:0.4" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="Opacity" />
<DoubleAnimation BeginTime="0:0:0.3" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="MaxHeight" />
<DoubleAnimation BeginTime="0:0:0.3" Duration="0:0:0.1" Storyboard.TargetName="pic" Storyboard.TargetProperty="MaxWidth" />
<DoubleAnimation BeginTime="0:0:0.4" Duration="0:0:0.1" Storyboard.TargetName="path" Storyboard.TargetProperty="Opacity" />
</Trigger.ExitActions>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
<!--ListBox樣式-->
<Style TargetType="ListBox">
<Setter Property="BorderBrush" Value="#BDD4F1"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="#F8F7F5"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<!--ListBoxItem樣式-->
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="#B5BABF"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Height" Value="28"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="back" BorderBrush="#F8F7F5" BorderThickness="0,1,0,1">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#F8F7F5" Offset="0.0"/>
<GradientStop Color="#F8F7F5" Offset="0.5"/>
<GradientStop Color="#F8F7F5" Offset="0.51"/>
<GradientStop Color="#F8F7F5" Offset="1"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter x:Name="content" Height="28" Margin="2" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="68" Duration="0:0:0.3" Storyboard.TargetName="content" Storyboard.TargetProperty="Height"/>
<DoubleAnimation To="68" Duration="0:0:0.3" Storyboard.TargetProperty="Height"/>
<ColorAnimation To="#F3C37C" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" />
<ColorAnimation To="#952B00" Duration="0:0:0.2" Storyboard.TargetProperty="(ListBoxItem.Foreground).(SolidColorBrush.Color)" />
<ColorAnimation To="#FFF" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation To="#FFEF99" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<ColorAnimation To="#FFE13F" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[2].(GradientStop.Color)" />
<ColorAnimation To="#FFF3B0" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[3].(GradientStop.Color)" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<DoubleAnimation BeginTime="0:0:0.4" Duration="0:0:0.2" Storyboard.TargetName="content" Storyboard.TargetProperty="Height"/>
<DoubleAnimation BeginTime="0:0:0.4" Duration="0:0:0.2" Storyboard.TargetProperty="Height"/>
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetProperty="(ListBoxItem.Foreground).(SolidColorBrush.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[2].(GradientStop.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[3].(GradientStop.Color)" />
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<ColorAnimation To="#D8E6F5" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" />
<ColorAnimation To="#617A98" Duration="0:0:0.2" Storyboard.TargetProperty="(ListBoxItem.Foreground).(SolidColorBrush.Color)" />
<ColorAnimation To="#F6F9FD" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation To="#E0EBF7" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<ColorAnimation To="#D7E5F6" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[2].(GradientStop.Color)" />
<ColorAnimation To="#F6F9FD" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[3].(GradientStop.Color)" />
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--以前教程中使用的按鈕樣式-->
<Style TargetType="Button">
<Setter Property="Foreground" Value="Black"/>
<!--修改模闆屬性-->
<!--控件模闆-->
<ControlTemplate TargetType="Button">
<!--背景色-->
<Border x:Name="back" Opacity="0.8" CornerRadius="3">
<Border.BitmapEffect>
<OuterGlowBitmapEffect Opacity="0.7" GlowSize="0" GlowColor="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Button.Background).(SolidColorBrush.Color)}" />
</Border.BitmapEffect>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1.5">
<GradientStop Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Button.Background).(SolidColorBrush.Color)}" Offset="0"/>
<GradientStop Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Button.Background).(SolidColorBrush.Color)}" Offset="0.4"/>
<GradientStop Color="#FFF" Offset="1"/>
<!--前景色及邊框-->
<Border x:Name="fore" BorderThickness="1" CornerRadius="3" BorderBrush="#5555">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#6FFF" Offset="0.5"/>
<GradientStop Color="#1111" Offset="0.51"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<!--按鈕内容-->
<ContentPresenter x:Name="content" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}">
<ContentPresenter.BitmapEffect>
<DropShadowBitmapEffect Color="#000" Direction="-90" ShadowDepth="2" Softness="0.1" Opacity="0.3" />
</ContentPresenter.BitmapEffect>
</ContentPresenter>
</Border>
<!--觸發器-->
<!--滑鼠移入移出-->
<DoubleAnimation To="6" Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)" />
<ColorAnimation To="#AFFF" BeginTime="0:0:0.2" Duration="0:0:0.2" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation To="#3FFF" BeginTime="0:0:0.2" Duration="0:0:0.2" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<!--按鈕按下彈起-->
<Trigger Property="IsPressed" Value="True">
<DoubleAnimation To="3" Duration="0:0:0.1" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)" />
<ColorAnimation To="#3AAA" Duration="0:0:0.1" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation To="#2111" Duration="0:0:0.1" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<!--按鈕失效-->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="#B444"/>
<DoubleAnimation To="0" Duration="0:0:0.3" Storyboard.TargetName="back" Storyboard.TargetProperty="(Border.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)" />
<DoubleAnimation To="1" Duration="0:0:0.1" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Opacity)" />
<DoubleAnimation To="-135" Duration="0:0:0.1" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Direction)" />
<ColorAnimation To="#FFF" Duration="0:0:0.3" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Color)" />
<ColorAnimation To="#D555" Duration="0:0:0.3" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" />
<ColorAnimation To="#CEEE" Duration="0:0:0.3" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" />
<ColorAnimation To="#CDDD" Duration="0:0:0.3" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.Background).(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" />
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Opacity)" />
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Direction)" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="content" Storyboard.TargetProperty="(ContentPresenter.BitmapEffect).(DropShadowBitmapEffect.Color)" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="fore" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" />
</Application.Resources>
</Application>
下面逐漸講解一下代碼。
首先需要引入一個命名空間,就是 FileInfo 類所在的 System.IO 命名空間,我們将它的别名定義為“c”。
DataTemplate 标記是為界面中出現的資料類型定義的顯示模闆,如果不指定 x:Key 的話,那麼界面上不管何處出現此類型的對象,都會轉為這樣的顯示方式。
WrapPanel 是一種簡單的容器元素,它會把它裡面的所有元素都橫着排列,排不下了就換一行接着排,這類似網頁的預設布局模式,很容易掌握。
WrapPanel.ToolTip 内定義的就是工具提示裡的那個縮略圖和文字了,其他代碼都很簡單就不多說了。
很多人覺得工具提示裡可以放圖檔是一件很神奇的事,的确很讓人驚喜,但是其實WPF元素的内容格式基本都是 Object 類型的,也就是說,你可以放一切你能想到的東西進去!按鈕、視訊、文檔乃至3D模型,都可以哦。
我們來看觸發器,這個觸發器定義的 Height 是誰的屬性呢?記得以前我們自定義樣式時怎麼顯示元素的内容嗎?對,ContentPresenter,這就是所有内容的總容器。
為什麼要在 ContentPresenter 高度為 68 的時候觸發動畫呢?這其實我是使了個歪點子~我沒找到資料内容相應上層元素屬性變化的方法,是以就用 ContentPresenter 高度變化與這邊産生關聯,進而間接響應 ListBox 那邊的 IsSelected 屬性變化。
動畫的内容就是把先前隐藏的圖檔和一行文字顯示并放大出來,沒什麼難點的。
行了,代碼部分講解完了,我們來談談如何完善這個程式。
這程式模樣不錯,但是有幾點很不爽:
1 顯示檔案的大小的機關是位元組,這讓人很暈。
2 選擇了非圖檔檔案不會顯示任何提示,隻是圖檔處空了。
3 FileInfo對象的内容在背景被更改不會及時反映到界面上。
對應的解決辦法:
1 采用自定義類,擷取必要的 FileInfo 對象的部分屬性值,定義專門用于以其它機關顯示檔案大小的屬性。
2 還是采用自定義類,擷取 FileInfo 對象的擴充名屬性,将之賦予自定義的一個依賴屬性上,依賴屬性可以被觸發器 Trigger 識别,這樣我們就可以依據擴充名來顯示不同的布局結構,并控制元素的隐現,比如選中視訊檔案可以播放視訊預覽,而選中一個普通檔案隻會顯示一種替代圖示。
3 依然是自定義類,隻有實作 INotifyPropertyChanged 接口的類型才可以提供更改通知,以維護雙向實時綁定。
WPF是個大舞台,我們可以做的還有很多。
<a href="http://files.cnblogs.com/SkyD/WPFListBox2.rar">源代碼下載下傳</a>