What is the proper way to implement VisualStates for multiple VisualStateGroups?

偶尔善良 提交于 2019-12-13 04:51:26

问题


This question is a follow-up to my previous question as well as this related question about how VisualStates work in WPF.

Currently, my understanding is that animating the same property within different VisualStateGroups can cause problems (see the linked questions).

To resolve these problems, it requires loop-holes to be taken advantage of. (Perhaps loop-hole isn't the correct term, but it appears that the solution isn't what the WPF designers intended.)

I'm wondering what is the correct way to animate the same property in multiple VisualStateGroups without causing adverse side-effects. If it is not possible, what is the correct route for achieving the same visual behavior for a control?

I was able to find some related documentation at MSDN:

The control is always in exactly one state per group. For example, a Button can have focus even when the mouse pointer is not over it, so a Button in the Focused state can be in the MouseOver, Pressed, or Normal state.

This leads me to a second question...

How can you provide a visual behavior that should only occur when two specific VisualStates are active?

Take for example a ToggleButton:

  • If the button is Checked, I would like to display Behavior 1.
  • If the button is Disabled, I would like to display Behavior 2.
  • Finally, if the button is Checked and Disabled, I would like to display Behavior 3.

In the above example, how would you go about rendering the third visual behavior?


回答1:


For the first part of your question, you'll want each state to interact with a different individual object for each instead of hitting the same one with each VisualState, as example;

    <VisualState x:Name="Disabled">
      <Storyboard>
          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DisabledState" 
                                  Storyboard.TargetProperty="(UIElement.Visibility)">
            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
          </ObjectAnimationUsingKeyFrames>
       </Storyboard>
    </VisualState>
    <VisualState x:Name="Checked">
      <Storyboard>
          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CheckedState" 
                                  Storyboard.TargetProperty="(UIElement.Visibility)">
            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
          </ObjectAnimationUsingKeyFrames>
       </Storyboard>
    </VisualState>

<!-- Each state interacts with its own object in your ControlTemplate ideally -->
<Border x:Name="CheckedState" Visibility="Collapsed"
        Background="Green"/>
<Border x:Name="DisabledState" Visibility="Collapsed"
        Background="White" Opacity=".5"/>

Instead of one object sharing a property change like;

<VisualState x:Name="Disabled">
  <Storyboard>
      <ColorAnimation d:IsOptimized="True"
                      Duration="0"
                      Storyboard.TargetName="Background"
                      Storyboard.TargetProperty="(SolidColorBrush.Color)"
                      To="White" />
   </Storyboard>
</VisualState>
<VisualState x:Name="Checked">
  <Storyboard>
      <ColorAnimation d:IsOptimized="True"
                      Duration="0"
                      Storyboard.TargetName="Background"
                      Storyboard.TargetProperty="(SolidColorBrush.Color)"
                      To="Green" />
   </Storyboard>
</VisualState>

<Border x:Name="Background" Background="Blue"/>

As per your second question, A VisualState is going to act as a bool in that it either is, or it isn't in that state. To share a declaration of a state you'd have to add a little more finesse with a MultiTrigger or a converter somewhere or something.

Hope this helps. Cheers

EDIT ADDITION:

So you also have available to you VisualTransition you could employ like;

 <VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="CommonStates">
    <VisualStateGroup.Transitions>
      <VisualTransition From="Normal"
        GeneratedDuration="0:0:0.2"
        To="Checked">
        <VisualTransition.GeneratedEasingFunction>
          <ExponentialEase EasingMode="EaseIn" Exponent="7" />
        </VisualTransition.GeneratedEasingFunction>
      </VisualTransition>
      <VisualTransition From="Checked"
        GeneratedDuration="0:0:0.2"
        To="Normal">
        <VisualTransition.GeneratedEasingFunction>
          <CircleEase EasingMode="EaseIn" />
        </VisualTransition.GeneratedEasingFunction>
      </VisualTransition>
    </VisualStateGroup.Transitions>
    <VisualState x:Name="Normal" />
    <!-- etc, etc, etc -->

So you can play with your different eases, your generated duration times, etc.



来源:https://stackoverflow.com/questions/25812630/what-is-the-proper-way-to-implement-visualstates-for-multiple-visualstategroups

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!