WPF: Triggers, VisualStateManager, and wpftriggers in WPF

Source: Internet
Author: User

WPF: Triggers, VisualStateManager, and wpftriggers in WPF

In the previous article "WPF: Introduction and practice of read-only dependency attributes", we introduced how to add read-only dependency attributes in a custom WPF control, in addition, it can be combined with attribute triggers to change the control style. In fact, in addition to attribute triggers, event triggers and data triggers (DataTrigger) in WPF are also involved ). In addition to triggers, you can also use VisualStates and VisualStateManager to control the control appearance switching.

This article briefly introduces Triggers and VisualStateManager, and introduces their differences. Understanding these differences will help us understand when to select a sender when developing custom controls, when to select VisualStateManager.

I. Triggers)

As mentioned above, there are three types of triggers:

  • Attribute Trigger (Trigger/MultiTrigger)
  • Event trigger)
  • Data trigger (DataTrigger/MultiDataTrigger)

These triggers are mainly used to change the widget's appearance or behavior when the value of a specified attribute changes or when an event is triggered. The property monitored by the trigger must be a dependency attribute, events must be routing events. They can be used in these places: DataTemplate, ControlTemplate, Style, and Inline attributes of the control.

1. Attribute triggers

Features:

For example:

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">    <Style.Triggers>        <Trigger Property="IsPressed" Value="True">            <Setter Property="Opacity" Value="0.5" />        </Trigger>        <Trigger Property="IsEnabled" Value="False">            <Setter Property="Foreground" Value="Red" />        </Trigger>    </Style.Triggers></Style>

MultiTrigger

Feature: when multiple attributes of an element or control change, Trigger is executed, for example:

<Style x:Key="MulitTriggerButtonStyle" TargetType="Button">    <Style.Triggers>        <MultiTrigger>            <MultiTrigger.Conditions>                <Condition Property="IsPressed" Value="True" />                <Condition Property="Background" Value="BlanchedAlmond" />            </MultiTrigger.Conditions>            <MultiTrigger.Setters>                <Setter Property="Foreground" Value="Blue" />                <Setter Property="BorderThickness" Value="5" />                <Setter Property="BorderBrush" Value="Blue" />            </MultiTrigger.Setters>        </MultiTrigger>    </Style.Triggers></Style>
2. event triggers

Features:

For example:

<Border  …>    <Border.Triggers>        <EventTrigger RoutedEvent="Mouse.MouseEnter">            <BeginStoryboard>               <Storyboard>                <ColorAnimation Duration="0:0:1" Storyboard.TargetName="MyBorder"                                 Storyboard.TargetProperty="Color" To="Gray" />               </Storyboard>            </BeginStoryboard>        </EventTrigger>    </Border.Triggers> </Border>
3. Data triggers

Feature: when the source value of the Data Binding meets the conditions specified by the Trigger, Trigger is executed. For example:

    <DataTemplate.Triggers>       <DataTrigger Binding="{Binding Path=Picture}" Value="{x:Null}">        <Setter TargetName="viewImage" Property="Source" Value="/Images/noImage.png" />        ……       </DataTrigger>    </DataTemplate.Triggers>

MultiDataTrigger

Feature: when multiple bound values meet the Conditions specified by Trigger's Conditions, Trigger is executed. For example:

<DataTemplate.Triggers>    <MultiDataTrigger>        <MultiDataTrigger.Conditions>            <Condition Binding="{Binding Path=Picture}" Value="{x:Null}" />            <Condition Binding="{Binding Path=Title}" Value="Waterfall" />        </MultiDataTrigger.Conditions>        <MultiDataTrigger.Setters>           <Setter TargetName="viewImage" Property="Source" Value="/Images/noImage.png"/>           <Setter TargetName="viewImage" Property="Opacity" Value="0.5" />           <Setter TargetName="viewText" Property="Background" Value="Brown" />        </MultiDataTrigger.Setters>    </MultiDataTrigger></DataTemplate.Triggers> 

Finally, it should be noted that only EventTrigger can be set for the Inline attribute of the control, such:

<Button>    <Button.Triggers>        <EventTrigger …>        </EventTrigger>    </Button.Triggers></Button>

Therefore, to sum up, the use cases of the above three types of triggers are to modify the widget's appearance or behavior when the property value of the control is changed or the event is triggered; and the property trigger has unique characteristics, that is, when the attribute value is restored, the style will be restored immediately.

After understanding this, when developing custom controls, we can control the display of controls by reasonably defining dependency properties, read-only dependency attributes, and routing events for custom controls. Next, let's look at visual statemanager, which can solve the same problem.

2. VisualStateManager

To use VisualStateManager, You need to define the VisualState. In the VisualState, You need to define the different states of the control and the styles in each state. Then, where appropriate in the code, we can use the GoToState of the VisusalStateManager class to switch to the corresponding State to implement style switching.

Therefore, in summary, the following four aspects are involved:

Each VisualState belongs to a status group (VisualStateGroup), that is, multiple visualstates can be defined in a VisualStateGroup. In addition, multiple VisualStateGroup can be defined. You need to emphasize that: the VisualState in the same VisualStateGroup is mutually exclusive, while the VisualState in different VisualStateGroup can coexist at the same time. Take Button as an example:

We can see that three visualstategroups are defined in it, namely, CommonStates (normal state), FocusStates (focus state), and ValidationStates (Verification State ), each VisualStateGroup has several visualstates. In CommonStates, the button can be Normal, MouseOver, or Pressed (only one of the three), but it can be displayed in conjunction with the VisualState in other VisualStateGroup, for example, when a button has a focus and the mouse moves over it, This combines two states: MouseOver and Focused. Some of the following code:

<ControlTemplate TargetType="Button">    <Grid>        <VisualStateManager.VisualStateGroups>            <VisualStateGroup x:Name="CommonStates">                <VisualStateGroup.Transitions>                    <VisualTransition GeneratedDuration="0:0:1" To="MouseOver" />                    <VisualTransition GeneratedDuration="0:0:1" To="Pressed" />                    <VisualTransition GeneratedDuration="0:0:1" To="Normal" />                </VisualStateGroup.Transitions>                <VisualState x:Name="Normal" />                <VisualState x:Name="MouseOver">                    <Storyboard>                        <ColorAnimation                            Storyboard.TargetName="BackgroundBorder"                            Storyboard.TargetProperty="Background.(SolidColorBrush.Color)"                            To="#A1D6FC"                            Duration="0" />                    </Storyboard>                </VisualState>                <VisualState x:Name="Pressed">                    <Storyboard>                        <ColorAnimation                            Storyboard.TargetName="BackgroundBorder"                            Storyboard.TargetProperty="Background.(SolidColorBrush.Color)"                            To="#FCA1A1"                            Duration="0" />                    </Storyboard>                </VisualState>            </VisualStateGroup>        </VisualStateManager.VisualStateGroups>        <Border            x:Name="BackgroundBorder"            Background="{TemplateBinding Background}"            BorderBrush="{TemplateBinding BorderBrush}"            BorderThickness="{TemplateBinding BorderThickness}"            SnapsToDevicePixels="true" />        <ContentPresenter            Margin="{TemplateBinding Padding}"            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"            Focusable="False"            RecognizesAccessKey="True"            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />    </Grid></ControlTemplate>

During the development of custom controls, we can also adopt the same principle, that is, to define VisualStateGroup, VisualState, and VisualTransition (optional) in XAML, and implement switching by using VisualStateManager. The following is the definition of VisualStates in a TextBox with a watermark function:

<VisualStateManager.VisualStateGroups>   <VisualStateGroup x:Name="WatermarkGroup">       <VisualStateGroup.Transitions>           <VisualTransition From="ShowWatermarkState" To="HideWatermarkState">              <Storyboard>                 <DoubleAnimation Storyboard.TargetName="PART_Watermark"                                  Storyboard.TargetProperty="Opacity" From="1"                                  To="0" Duration="0:0:2" />               </Storyboard>                                                    </VisualTransition>            <VisualTransition From="HideWatermarkState" To="ShowWatermarkState">               <Storyboard>                  <DoubleAnimation Storyboard.TargetName="PART_Watermark"                                   Storyboard.TargetProperty="Opacity" From="0"                                   To="1" Duration="0:0:2" />               </Storyboard>            </VisualTransition>         </VisualStateGroup.Transitions>         <VisualState x:Name="ShowWatermarkState">            <Storyboard>               <ObjectAnimationUsingKeyFrames Duration="0:0:0"                             Storyboard.TargetName="PART_Watermark"                             Storyboard.TargetProperty="(UIElement.Visibility)">                  <DiscreteObjectKeyFrame KeyTime="0:0:0"                             Value="{x:Static Visibility.Visible}"/>               </ObjectAnimationUsingKeyFrames>            </Storyboard>         </VisualState>         <VisualState x:Name="HideWatermarkState">            <Storyboard>               <ObjectAnimationUsingKeyFrames Duration="0:0:0"                             Storyboard.TargetName="PART_Watermark"                             Storyboard.TargetProperty="(UIElement.Visibility)">                   <DiscreteObjectKeyFrame KeyTime="0:0:0"                             Value="{x:Static Visibility.Collapsed}"/>               </ObjectAnimationUsingKeyFrames>            </Storyboard>        </VisualState>                                    </VisualStateGroup></VisualStateManager.VisualStateGroups>

It can be seen that it defines the WatermarkGroup, and defines the ShowWatermarkState and HideWatermarkState visualstates. In addition, the defined VisualTransition can be used to implement switching between the two States, watermark text fades in and out.

Finally, in the Code, call the VisualStateManager. GoToState method to switch to the appropriate State:

private void UpdateState(){   bool textExists = Text.Length > 0;   var watermark = GetTemplateChild("PART_Watermark") as FrameworkElement;   var state = textExists || IsFocused ? "HideWatermarkState" : "ShowWatermarkState";    VisualStateManager.GoToState(this, state, true);} protected override void OnGotFocus(RoutedEventArgs e){   base.OnGotFocus(e);   UpdateState();} protected override void OnLostFocus(RoutedEventArgs e){   base.OnLostFocus(e);   UpdateState();}

Finally, when will the status be switched? Generally, this includes but is not limited to the following occasions or places:

  • In the OnApplyTemplate method (that is, when the template is applied );
  • When a property is changed (it can be called in PropertyChangedCallback );
  • When an event occurs;
Iii. Differences between Triggers and VisualStateManager

We can see that both Trigger and VisualStateManager can accomplish the same thing, but they are also different, mainly including the following:

Summary

This article mainly discusses Triggers and VisualStateManager in WPF. When designing custom controls, they can be supplemented by the function of completing style switching; we have introduced the usage and key points of the two. Finally, we have summarized their differences. When we understand their respective characteristics and their differences, we can design our custom controls selectively and conveniently, and use them freely during WPF development.

 

References:

VisualStateManager and alternative to Triggers

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.