Brushes画刷集合
- 主框架界面
实现效果:
- 左侧的可折叠/展开选项单。
- 界面选项单内容的层次结构TreeView
- 根据选择页面项 导航展示各页面内容
关注词:
- CommandBinding+InputBinding组合
- Expander控件标题+内容自定义
- TreeView背景毛玻璃+Item玻璃效果
- Xml+分层数据模板
- 菜单项命令的输入绑定及命令绑定组合
- 设置当前命令为系统已设定的退出命令,并在之后附加执行命令方法
- 当前命令的输入命令为ALT+F4键盘绑定,它们一起组合成通过键盘操作即可执行自定义操作。
<MenuItem Header="_File" >
<MenuItem Command="{x:Static examples:SampleViewer.ExitCommand}">
<MenuItem.CommandBindings>
<CommandBinding
Command="{x:Static examples:SampleViewer.ExitCommand}"
Executed="ExecuteExitCommand" />
</MenuItem.CommandBindings>
<MenuItem.InputBindings>
<KeyBinding
Command="{x:Static examples:SampleViewer.ExitCommand}"
Key="F4" Modifiers="Alt" />
</MenuItem.InputBindings>
</MenuItem>
</MenuItem>
- Expander控件中标题内容自定义
1、控件扩展方向设为左侧,标题中文本方向设置LayoutTransform转换90°垂直
<Expander ExpandDirection="Left">
<Expander.Header>
<TextBlock Foreground="#99000000"
FontFamily="Verdana" FontWeight="Bold" FontSize="24pt"
Text="Contents">
<TextBlock.LayoutTransform>
<RotateTransform Angle="90" />
</TextBlock.LayoutTransform>
</TextBlock>
</Expander.Header>
2、控件内容区包含设置两个Border边框,其背景色使用图像画刷ImageBrush资源填充,显示出青灰色及白色图像画刷的叠加效果。
3、边框内设置TreeView控件,其控件的上下方向键导航设置为循环,默认为Continue。
4、TreeView控件设置背景色透明,子项模板ItemTemplate:分层数据模板HierarchicalDataTemplate;子项ItemContainerStyle
5、数据绑定源key为XmlDataProvider提供,其Source为xml文件、路径为根Examples的空引用。
6、TreeView设有事件触发器,选择改变时会触发Fame区不透明度为0动画,即显示为空白区。此项动画由当前状态验证CurrentStateInvalidated绑定的方法判断。
<!-- Lists the different brush samples. The list is
defined in the sampleResources\TOC.xml file. -->
<TreeView Name="myPageList"
KeyboardNavigation.DirectionalNavigation="Cycle"
BorderBrush="Transparent"
Background="Transparent"
ItemTemplate="{DynamicResource ExamplesDataTemplate}"
ItemContainerStyle="{StaticResource TreeViewItemHeaderStyle}"
SelectedValuePath="Example">
<TreeView.ItemsSource>
<Binding Source="{StaticResource ExampleData}" XPath="*"/>
</TreeView.ItemsSource>
<TreeView.Triggers>
<EventTrigger RoutedEvent="TreeView.SelectedItemChanged">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myFrame"
Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:0.1"
CurrentStateInvalidated="TransitionAnimationStateChanged"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TreeView.Triggers>
</TreeView>
TreeView选择子项时导航到对应页面情况:
- 在页切换间有个0.1s的小动画,使Frame显示区为空白。
- 在动画线开始后ClockState.Filling下就进行后续判断操作
private void TransitionAnimationStateChanged(object sender, EventArgs args)
{
var transitionAnimationClock = (AnimationClock) sender;
if (transitionAnimationClock.CurrentState == ClockState.Filling)
{
FadeEnded();
}
}
Frame区显示判断:选择项的值转换为Xml元素,获取其特性 Uri值导航页面显示。若值为空则保持动画后的空白模样。
private void FadeEnded()
{
var el = (XmlElement) myPageList.SelectedItem;
var att = el.Attributes["Uri"];
if (att != null)
{
myFrame.Navigate(new Uri(att.Value, UriKind.Relative));
}
else
{
myFrame.Content = null;
}
}
页面导航时Frame对空白恢复显示:
代码获取动画资源,设置到Frame的不透明度属性上。
private void MyFrameNavigated(object sender, NavigationEventArgs args)
{
var myFadeInAnimation = (DoubleAnimation) Resources["MyFadeInAnimationResource"];
myFrame.BeginAnimation(OpacityProperty, myFadeInAnimation, HandoffBehavior.SnapshotAndReplace);
}
- TreeViewItem样式内容:
TreeViewItem自定义控件模板:
以下图中TreeView的2层背景色(白色)是背景方框取消后。
1、最底层方框:透明填充,大圆角RadiusXY=10,Rectangle.Stroke默认为null;当选中为焦点时,变现Stroke设为亮蓝。
<Rectangle x:Name="outerRectangle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Fill="{TemplateBinding Background}" RadiusX="10" RadiusY="10"
StrokeThickness="5" Grid.ColumnSpan="2" Opacity="1" />
<Trigger Property="IsFocused" Value="true">
<Setter Property="Rectangle.Stroke"
Value="{x:Static SystemColors.HighlightBrush}"
TargetName="outerRectangle" />
2、次层方框显示为玻璃效果,使用图像ImageBrush
填充,但Opacity为0不显示,设置圆角10,Stroke宽度为1,但还是设置了上透明下灰线变色,与方框的外发光OuterGlowBitmapEffect及凹凸BevelBitmapEffect位图效果进行适配;当选择焦点时,触发器是方框的Opacity=1显现效果。
3、标题前部的图标(收缩为十字,展开为一字)样式:
- 扩展收缩IsChecked值绑定到自身已设置值。
- 触发器设置探测本项无子项时即图标显示隐藏。
- 点击事件ButtonBase.ClickMode设置到为按下按钮触发
<ToggleButton
Name="ExpanderIcon"
Grid.Row="0" Grid.Column="0"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press" />
<Trigger Property="HasItems"
Value="False">
<Setter TargetName="ExpanderIcon"
Property="Visibility"
Value="Hidden"/>
以上切换按钮ToggleButton图标的样式ExpandCollapseToggleStyle:
- 设置好长宽,不可焦点属性,其模板设置Path及Data值
- ControlTempalte.Triggers又设置点击时的十/一字切换。
<Style x:Key="ExpandCollapseToggleStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable"
Value="False"/>
<Setter Property="MinWidth"
Value="19"/>
<Setter Property="MinHeight"
Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border MinWidth="19"
MinHeight="13"
Background="{StaticResource GlassBrushResource}">
<Border MinWidth="9"
MinHeight="9"
BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"
Background="Transparent"
SnapsToDevicePixels="true">
<Path x:Name="ExpandPath"
Stretch="Uniform"
Margin="1,1,1,1"
Fill="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
<Border.BitmapEffect>
<DropShadowBitmapEffect />
</Border.BitmapEffect>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Data"
TargetName="ExpandPath"
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
4、标题头Icon处的另一个图像:
- 与上个十/一图标一起设置,但设置可见性隐藏;绑定源为DrawingImage-DrawingGroup-GeometryDrawing内容。
- 当本项触发无子项(下级内容)事件时,设置可见。
<Image
Name="ItemIcon"
Grid.Row="0" Grid.Column="0"
Source="{StaticResource PaperDrawingImage}"
Visibility="Hidden"
Margin="2" />
5、标题头内容显示:名称设为PART_Header,内容源为Header
<ContentPresenter
Name="PART_Header" Grid.Column="1" Margin="10,5,10,5"
TextBlock.Foreground="Black"
ContentSource="Header" />
6、点击Item展开和收缩以分层使用的ToggleButton(必备):
- 显示分层结构的标题头样式,绑定上级IsExpanded,内容控件中方框背景色为透明
- 当本项没有子项时,触发可见性隐藏,即点击本层一次时,下层展开显示或隐藏。
<ToggleButton
Name="Expander"
Grid.Column="0" Grid.ColumnSpan="2"
Visibility="Visible"
IsChecked="{Binding Path=IsExpanded,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<ToggleButton.Template>
<ControlTemplate>
<Rectangle Fill="Transparent" />
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Trigger Property="HasItems"
Value="False">
<Setter TargetName="Expander"
Property="Visibility"
Value="Hidden"/>
7、Items主容器(必备)
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1" />
8、TreeViewItem控件触发器ControlTemplate.Triggers:
- 当鼠标选择及悬浮控件上时,开始执行或退出执行对次层方框的透明度动画
- 当选中/取消选中本项事件触发时,执行玻璃样式的透明度、边框、位图颜色动画
- 收缩/扩展时触发属性设置主容器的可见度为Collapsed
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="true" />
<Condition Property="IsSelected" Value="False" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="UncheckedBeginStoryboard" />
<BeginStoryboard Name="MouseOverBeginStoryboard">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="Opacity"
To="0.75"
Duration="0:0:0.1" />
<DoubleAnimation
Storyboard.TargetName="glassCubeBrush"
Storyboard.TargetProperty="Opacity"
From="0.75" To="0.5" AutoReverse="True"
RepeatBehavior="Forever"
Duration="0:0:0.75" />
</Storyboard>
</BeginStoryboard>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="MouseOverBeginStoryboard" />
</MultiTrigger.ExitActions>
</MultiTrigger>
<EventTrigger RoutedEvent="TreeViewItem.Selected">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="Opacity"
To="0.75"
Duration="0:0:0.1" />
<DoubleAnimation
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="StrokeThickness"
To="2"
Duration="0:0:0.1" />
<ColorAnimation
Storyboard.TargetName="glowBitmapEffect"
Storyboard.TargetProperty="GlowColor"
To="{x:Static SystemColors.HighlightColor}"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="TreeViewItem.Unselected">
<BeginStoryboard Name="UncheckedBeginStoryboard">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="Opacity"
To="0"
Duration="0:0:0.1" />
<DoubleAnimation
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="StrokeThickness"
To="1"
Duration="0:0:0.1" />
<ColorAnimation
Storyboard.TargetName="glowBitmapEffect"
Storyboard.TargetProperty="GlowColor"
To="{x:Static SystemColors.ControlColor}"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Rectangle.Stroke"
Value="{x:Static SystemColors.HighlightBrush}"
TargetName="outerRectangle" />
<Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
</Trigger>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost"
Property="Visibility"
Value="Collapsed"/>
</Trigger>
可改进:Treeview内容应有滚动条及在鼠标在内容区能滚动操作,需控件处在ScrollView中显示
关注问题:
- 点击TreeView项时,怎样引导Frame区的改变及显示。
- 选择TreeView的标题时,怎样判断选择项及Frame变成空白区
扩展:
-
KeyboardNavigation 类:在可获得焦点的对象之间提供逻辑和方向导航。
- KeyboardNavigation 类负责在按下导航键之一时执行默认键盘焦点导航。 这些导航键为:Tab、Shift+Tab、Ctrl+Tab、Ctrl+Shift+Tab、向上键、向下键、向左键和向右键。
- 逻辑导航的一个示例是使用 Tab 键来移动焦点。方向导航的一个示例是使用箭头键来移动焦点。
-
Timeline.CurrentStateInvalidated 事件:在时间线 Clock 的 CurrentState 属性更新时发生。
- 如果希望在时间线的 Clock 开始、停止或填充时收到通知,请使用 CurrentStateInvalidated 事件。
- 暂停 Clock 不会更改其 CurrentState。 若要在时钟变为暂停时收到通知,请使用 CurrentGlobalSpeedInvalidated 事件。
- 虽然此事件在 ClockState 变为无效时发生,但并不一定意味着 ClockState 已更改:在同一个计时周期中将 Clock 从 Active 切换为 Filling,然后再切换为 Active 将导致引发此事件,但它的 CurrentState 属性实际并不会更改。
- EventHandler 事件处理程序的 Object 参数是为此时间线创建的 Clock。虽然此事件处理程序看上去与时间线相关联,但它实际向为此时间线创建的 Clock 注册。