在我们的WPF应用程序中,我们有许多Style
个ControlTemplate
s,需要为Binding
值设置动画。由于只有Freezable
个值可以参与Storyboard
s,因此我们必须创建具有不同绑定值的多个对象,并在动画中切换其可见性。这是我们的按钮之一:
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Grid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
<VisualTransition GeneratedDuration="0" To="MouseOver"/>
<VisualTransition GeneratedDuration="0" To="Pressed"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="BorderOver">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconUp">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconOver">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="BorderOver">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="BorderDown">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconUp">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconOver">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconDown">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconDisabled">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconUp">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="BorderOver" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Opacity="0"/>
<Border x:Name="BorderDown" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Background="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}" Opacity="0"/>
<Path x:Name="IconUp" Data="M14.077,9.772C11.634,9.772 9.652,11.753 9.652,14.197 9.652,16.641 11.634,18.622 14.077,18.622 16.521,18.622 18.502,16.641 18.502,14.197 18.502,11.753 16.521,9.772 14.077,9.772 M28,12L28,16 24.085,16C23.84,17.369,23.325,18.643,22.592,19.763L25.313,22.485 22.485,25.314 19.791,22.62C18.668,23.383,17.383,23.924,16,24.189L16,28 12,28 12,24.163C10.638,23.88,9.378,23.322,8.274,22.554L5.514,25.314 2.686,22.485 5.504,19.668C4.802,18.57,4.306,17.331,4.068,16L0,16 0,12 4.144,12C4.427,10.722,4.943,9.533,5.656,8.485L2.686,5.515 5.514,2.686 8.513,5.684C9.558,5,10.734,4.499,12,4.236L12,0 16,0 16,4.21C17.285,4.456,18.48,4.946,19.545,5.626L22.485,2.686 25.313,5.515 22.431,8.397C23.176,9.467,23.718,10.685,24.008,12z" Fill="{TemplateBinding Foreground}" Height="12" Width="12" Stretch="Fill" Margin="0,0,4.5,0" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<Path x:Name="IconOver" Data="M14.077,9.772C11.634,9.772 9.652,11.753 9.652,14.197 9.652,16.641 11.634,18.622 14.077,18.622 16.521,18.622 18.502,16.641 18.502,14.197 18.502,11.753 16.521,9.772 14.077,9.772 M28,12L28,16 24.085,16C23.84,17.369,23.325,18.643,22.592,19.763L25.313,22.485 22.485,25.314 19.791,22.62C18.668,23.383,17.383,23.924,16,24.189L16,28 12,28 12,24.163C10.638,23.88,9.378,23.322,8.274,22.554L5.514,25.314 2.686,22.485 5.504,19.668C4.802,18.57,4.306,17.331,4.068,16L0,16 0,12 4.144,12C4.427,10.722,4.943,9.533,5.656,8.485L2.686,5.515 5.514,2.686 8.513,5.684C9.558,5,10.734,4.499,12,4.236L12,0 16,0 16,4.21C17.285,4.456,18.48,4.946,19.545,5.626L22.485,2.686 25.313,5.515 22.431,8.397C23.176,9.467,23.718,10.685,24.008,12z" Fill="{TemplateBinding BorderBrush}" Height="12" Width="12" Stretch="Fill" Margin="0,0,4.5,0" VerticalAlignment="Center" HorizontalAlignment="Right" Opacity="0"/>
<Path x:Name="IconDown" Data="M14.077,9.772C11.634,9.772 9.652,11.753 9.652,14.197 9.652,16.641 11.634,18.622 14.077,18.622 16.521,18.622 18.502,16.641 18.502,14.197 18.502,11.753 16.521,9.772 14.077,9.772 M28,12L28,16 24.085,16C23.84,17.369,23.325,18.643,22.592,19.763L25.313,22.485 22.485,25.314 19.791,22.62C18.668,23.383,17.383,23.924,16,24.189L16,28 12,28 12,24.163C10.638,23.88,9.378,23.322,8.274,22.554L5.514,25.314 2.686,22.485 5.504,19.668C4.802,18.57,4.306,17.331,4.068,16L0,16 0,12 4.144,12C4.427,10.722,4.943,9.533,5.656,8.485L2.686,5.515 5.514,2.686 8.513,5.684C9.558,5,10.734,4.499,12,4.236L12,0 16,0 16,4.21C17.285,4.456,18.48,4.946,19.545,5.626L22.485,2.686 25.313,5.515 22.431,8.397C23.176,9.467,23.718,10.685,24.008,12z" Fill="{TemplateBinding Background}" Height="12" Width="12" Stretch="Fill" Margin="0,0,4.5,0" VerticalAlignment="Center" HorizontalAlignment="Right" Opacity="0"/>
<Path x:Name="IconDisabled" Data="M14.077,9.772C11.634,9.772 9.652,11.753 9.652,14.197 9.652,16.641 11.634,18.622 14.077,18.622 16.521,18.622 18.502,16.641 18.502,14.197 18.502,11.753 16.521,9.772 14.077,9.772 M28,12L28,16 24.085,16C23.84,17.369,23.325,18.643,22.592,19.763L25.313,22.485 22.485,25.314 19.791,22.62C18.668,23.383,17.383,23.924,16,24.189L16,28 12,28 12,24.163C10.638,23.88,9.378,23.322,8.274,22.554L5.514,25.314 2.686,22.485 5.504,19.668C4.802,18.57,4.306,17.331,4.068,16L0,16 0,12 4.144,12C4.427,10.722,4.943,9.533,5.656,8.485L2.686,5.515 5.514,2.686 8.513,5.684C9.558,5,10.734,4.499,12,4.236L12,0 16,0 16,4.21C17.285,4.456,18.48,4.946,19.545,5.626L22.485,2.686 25.313,5.515 22.431,8.397C23.176,9.467,23.718,10.685,24.008,12z" Fill="#FF999999" Height="12" Width="12" Stretch="Fill" Margin="0,0,4.5,0" VerticalAlignment="Center" HorizontalAlignment="Right" Opacity="0"/>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Right" Margin="4.5,1,21,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" Width="Auto"/>
</Grid>
</ControlTemplate>
这些按钮与DynamicResources
es一起使用。像这样:
<Button Content="..." Style="{DynamicResource hkbtnSettings}" Background="{DynamicResource InterfaceHeaderColor}" Foreground="{DynamicResource InterfaceBodyColor}" BorderBrush="{DynamicResource InterfaceAccentColor}"/>
我们的应用程序中存在一些渲染性能问题。我想知道我们是否可以在性能方面优化这些模板?
答案 0 :(得分:1)
1)避免使用动态资源:请参阅此Link
动态资源比静态资源具有更多的性能开销,因为它每次请求或需要时都会查找资源。
2)触发器与视觉状态:请参阅此Link
每个视觉状态更改都会启动一个故事板,而该故事板又包含更多时间轴对象。当然,这比仅仅在触发器中设置属性消耗更多的时间和内存
3)形状与控制请参阅此Link
我们不能将子元素添加到形状因此它比控件更轻...因此在示例中我使用Rectangle而不是Border。
4) x:姓名与姓名请参阅此Link
将x:名称替换为“名称”在模板中。
5)避免提供不必要的“名称”属性:请参阅此link
在示例中,我删除了网格名称。
6)优化元素数量请参阅此link
XAML可以显示数千个对象,您可以通过减少模板中的元素数量来进行模板布局和渲染场景。
考虑所有这些要点后的最终模板
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Name="Rectangle" StrokeThickness="{TemplateBinding BorderThickness}" Margin="{TemplateBinding Padding}" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" Opacity="0"/>
<Path Name="Icon" Data="M14.077,9.772C11.634,9.772 9.652,11.753 9.652,14.197 9.652,16.641 11.634,18.622 14.077,18.622 16.521,18.622 18.502,16.641 18.502,14.197 18.502,11.753 16.521,9.772 14.077,9.772 M28,12L28,16 24.085,16C23.84,17.369,23.325,18.643,22.592,19.763L25.313,22.485 22.485,25.314 19.791,22.62C18.668,23.383,17.383,23.924,16,24.189L16,28 12,28 12,24.163C10.638,23.88,9.378,23.322,8.274,22.554L5.514,25.314 2.686,22.485 5.504,19.668C4.802,18.57,4.306,17.331,4.068,16L0,16 0,12 4.144,12C4.427,10.722,4.943,9.533,5.656,8.485L2.686,5.515 5.514,2.686 8.513,5.684C9.558,5,10.734,4.499,12,4.236L12,0 16,0 16,4.21C17.285,4.456,18.48,4.946,19.545,5.626L22.485,2.686 25.313,5.515 22.431,8.397C23.176,9.467,23.718,10.685,24.008,12z" Fill="{TemplateBinding Foreground}" Height="12" Width="12" Stretch="Fill" Margin="0,0,4.5,0" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<ContentPresenter Name="contentPresenter" HorizontalAlignment="Right" Margin="4.5,1,21,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" Width="Auto"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Rectangle" Property="Opacity" Value="1"></Setter>
<Setter TargetName="Icon" Property="Fill" Value="{Binding Path=BorderBrush,RelativeSource={RelativeSource TemplatedParent}}"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Rectangle" Property="Opacity" Value="1"></Setter>
<Setter TargetName="Rectangle" Property="Fill" Value="{Binding Path=BorderBrush,RelativeSource={RelativeSource TemplatedParent}}"></Setter>
<Setter TargetName="Icon" Property="Fill" Value="{Binding Path=Background,RelativeSource={RelativeSource TemplatedParent}}"></Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="contentPresenter" Value="0.5"></Setter>
<Setter TargetName="Icon" Property="Fill" Value="#FF999999"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
其他一些有用的链接
1)http://www.centigrade.de/en/blog/article/wpf-performance-2/