views:

51

answers:

2

Hi, I'm new to WPF, and I would like to know how to reuse some annoying xaml I have to avoid duplicating.

<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi!" Focusable="False" IsTabStop="False"/>
<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi 2!" Focusable="False" IsTabStop="False"/>

I'd really like to use something like this template:

<Style TargetType="{x:Type Button}" x:Key="ButtonTemplate">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid x:Name="btGrid">
                            <Path Cursor="Hand" HorizontalAlignment="Left" Stretch="Fill" Stroke="{x:Null}" Opacity="0" x:Name="path"/>
                            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" Visibility="Hidden" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonDown">
                                <EventTrigger.Actions>
                                    <BeginStoryboard>
                                        <Storyboard SlipBehavior="Slip" BeginTime="00:00:00">
                                            <MediaTimeline Source="{Binding StringFormat={}, Path=Name}" Storyboard.TargetName="{Binding StringFormat={}_wma, Path=Name}"/>
                                                    <ObjectAnimationUsingKeyFrames    Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0">
                <DiscreteObjectKeyFrame.Value>
                    <Visibility>
                        Visible
                    </Visibility>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger.Actions>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonUp">
                                <EventTrigger.Actions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0">
                <DiscreteObjectKeyFrame.Value>
                    <Visibility>
                        Hidden
                    </Visibility>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger.Actions>
                            </EventTrigger>
                            <Trigger Property="IsFocused" Value="True"/>
                            <Trigger Property="IsDefaulted" Value="True"/>
                            <Trigger Property="IsMouseOver" Value="True"/>
                            <Trigger Property="IsPressed" Value="True"/>
                            <Trigger Property="IsEnabled" Value="False"/>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

And I'd like the {Binding StringFormat={}, Path=Name} to point button's name, e.g. "MyButton", "MyButton2", etc.

When I run this code I get the error "Cannot freeze this Storyboard timeline tree for use across threads." :/ I understand this is because I use binding in a storyboard, correct? I don't know what to do to make this work.

Also, I'd like to make the ToggleVisibility of the image a template as well, that accepts once "Visible" and once "Hidden" values. Thanks in advance!

A: 

Hi,

You could always define properties other than Template in your style too.

    <Style TargetType="{x:Type Button}"
           x:Key="ButtonTemplate">
        <Setter Property="Cursor" Value="Hand" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="Margin" Value="0,0,0,0" />
        <Setter Property="Width" Value="286" />
        <Setter Property="Focusable" Value="False" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    ...
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Which makes your code look like

    <Button x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Content="hi!" />
    <Button x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Content="hi 2!" />
decyclone
Hi, thank you for your reply, but this doesn't work... I still get the same {"Cannot freeze this Storyboard timeline tree for use across threads."} exception.
Rita
Ok,What do you mean by this line :<MediaTimeline Source="{Binding StringFormat={}, Path=Name}" Storyboard.TargetName="{Binding StringFormat={}_wma, Path=Name}"/>
decyclone
A: 

Yeah creating a style with target type to as button would do the trick.

Tip:It is always a good practice to write all the styling informations such as border, background, templates, etc., under the resource section of your code and apply them on the controls. It'll give good readability.

HTH :)

Avatar