简体   繁体   English

单击按钮后如何更改模板

[英]How to change templates after clicking Button

I would like to change view of button after button is clicked. 我想在单击按钮后更改按钮的视图。 For example, I have two templates beforeClicking and afterClicking : 例如,我有两个模板beforeClickingafterClicking

<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button" x:Name="beforeClicking">
                <Border Name="border" Background="Transparent" BorderThickness="1" BorderBrush="Black">
                    <ContentPresenter/>
                </Border>                    
            </ControlTemplate>
            <!--It is not permitted, but that is pseudocode(what I want)
             <ControlTemplate TargetType="Button" x:Name="afterClicking">
                <Border Name="border" Background="Transparent" BorderThickness="10" BorderBrush="Black">
                    <ContentPresenter/>
                </Border>                    
            </ControlTemplate>
            -->
        </Setter.Value>
    </Setter>
</Style>

What I want is when button is not clicked, then a template beforeClicking should be permanently used and nothing(template or view) should not be altered. 我想要的是未单击按钮时,则应永久使用模板beforeClicking并且不应更改任何内容(模板或视图)。 However, if user clicks, then button should use a template afterClicking permanently and the view of button should not be altered. 但是,如果用户单击,则按钮应永久使用afterClicking之后的模板,并且按钮的视图不应更改。

That is at the first click the button uses template afterClicking . 即在第一次单击时,按钮使用模板afterClicking At the second click the button uses template beforeClicking . 在第二次单击时,按钮使用模板beforeClicking At the third click the button uses template afterClicking . 第三次单击时,按钮使用模板afterClicking At the fourth click the button uses template afterClicking . 在第四次单击时,按钮使用afterClicking模板。 And so on. 等等。

I would like to get such behavior just by XAML since MVVM approach is used. 由于使用了MVVM方法,我只想通过XAML来获得这种行为。

How to achieve such a behavior? 如何实现这种行为?

You can handle a click using an EventTrigger. 您可以使用EventTrigger处理点击。 In an event trigger you provide a Storyboard, but in a Storyboard you can't change the Template. 在事件触发器中,您提供情节提要,但在情节提要中不能更改模板。

You could do this in an attached property, but looking at your example, you don't need to, and more typically, you'd affect individual properties: 您可以在附加属性中执行此操作,但是查看您的示例,则不需要这样做,更典型地,您会影响单个属性:

<Style TargetType="Button">
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border" Background="Transparent" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Black">
                    <ContentPresenter/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <EventTrigger RoutedEvent="Click">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness">
                            <DiscreteThicknessKeyFrame Value="10" KeyTime="0" />
                        </ThicknessAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
    </Style.Triggers>
</Style>

==After discussion: ToggleButton version:== ==讨论后:ToggleButton版本:==

<Window.Resources>
    <Style TargetType="ToggleButton">
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ToggleButton">
                    <Border Name="border" Background="Transparent" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Black">
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsChecked" Value="True">
                <Setter Property="BorderThickness" Value="10" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <ToggleButton>Hello World</ToggleButton>
</Grid>

If I were you I would use System.Windows.Interactivity.Behavior rather than EventTriggers , unfortunately EventTriggers are the only way for you to associate in xaml event with operation, the only problem is that EventTriggers only work with TriggerAction objects and you can't create your TriggerAction . 如果我是我,我将使用System.Windows.Interactivity.Behavior而不是EventTriggers ,不幸的是, EventTriggers是将xaml事件与操作关联的唯一方法,唯一的问题是EventTriggers仅与TriggerAction对象一起使用,而您不能创建您的TriggerAction This because it is an abstract class which abstract methods are internal and not overridable from outside PresentationFramework library. 这是因为它是一个抽象类,其抽象方法是内部的,并且不能从PresentationFramework库外部覆盖。 Here is an example of how prepare your Behavior class: 这是一个如何准备行为类的示例:

public class ChangeTemplateBehavior : System.Windows.Interactivity.Behavior<Button>
{
    public static readonly DependencyProperty ControlTemplate1Property = DependencyProperty.Register("ControlTemplate1", typeof(ControlTemplate), typeof(ChangeTemplateBehavior), new PropertyMetadata(default(ControlTemplate)));

    public ControlTemplate ControlTemplate1
    {
        get
        {
            return (ControlTemplate)GetValue(ControlTemplate1Property);
        }
        set
        {
            SetValue(ControlTemplate1Property, value);
        }
    }

    public static readonly DependencyProperty ControlTemplate2Property = DependencyProperty.Register("ControlTemplate2", typeof(ControlTemplate), typeof(ChangeTemplateBehavior), new PropertyMetadata(default(ControlTemplate)));

    public ControlTemplate ControlTemplate2
    {
        get
        {
            return (ControlTemplate)GetValue(ControlTemplate2Property);
        }
        set
        {
            SetValue(ControlTemplate2Property, value);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.Click += AssociatedObject_Click;
    }

    void AssociatedObject_Click(object sender, RoutedEventArgs e)
    {
        if (this.AssociatedObject.Template == this.ControlTemplate2)
        {
            this.AssociatedObject.Template = this.ControlTemplate1;
        }
        else
        {
            this.AssociatedObject.Template = this.ControlTemplate2;
        }
    }
}

And here is an example of how to write your xaml code: 这是一个如何编写您的xaml代码的示例:

<Window x:Class="StackoverflowHelpWPF5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:[YOURLOCALNAMESPACEHERE]"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>

        <ControlTemplate TargetType="Button" x:Key="beforeClicking">
            <Border Name="border" Background="Transparent" BorderThickness="1" BorderBrush="Black">
                <ContentPresenter/>
            </Border>
        </ControlTemplate>

        <ControlTemplate TargetType="Button" x:Key="afterClicking">
            <Border Name="border" Background="Transparent" BorderThickness="10" BorderBrush="Black">
                <ContentPresenter/>
            </Border>                    
        </ControlTemplate>

    </Window.Resources>

    ...

    <Button  Template="{StaticResource beforeClicking}" >
            <i:Interaction.Behaviors>
                <local:ChangeTemplateBehavior ControlTemplate1="{StaticResource afterClicking}" ControlTemplate2="{StaticResource beforeClicking}"></local:ChangeTemplateBehavior>
            </i:Interaction.Behaviors>
    </Button>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM