优化控件模板以设置动画绑定

时间:2014-12-26 09:39:23

标签: wpf xaml themes controltemplate

在我们的WPF应用程序中,我们有许多StyleControlTemplate 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}"/>  

我们的应用程序中存在一些渲染性能问题。我想知道我们是否可以在性能方面优化这些模板?

1 个答案:

答案 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/

2)http://wpftutorial.net/10PerformanceTips.html