传播VisualState更改的最佳方法

时间:2010-08-19 20:41:02

标签: silverlight visualstatemanager visualstates

我目前正面临一个场景,我不确定最好的处理方式是什么。

情境:

  1. ControlA有两个自定义视觉状态,我们称之为“StateOn”和“StateOff”。
  2. 我现在在ControlA上应用模板,我们称之为“templateA”。
  3. “templateA”在其下面有一个ControlB类型的控件(谁不知道StateOn / Off)。
  4. ControlB有一个模板,用于处理ControlA的视觉状态更改,即StateOn和StateOff。
  5. 问题:
    ControlB不会接收对在ControlA上触发的VisualStates的更改,因此不会发生可视更改。

    我认为问题与作为控件(ControlB)的根元素有关,它不会在所需状态上触发getostate。但是,我想知道将ControlA的visualstate更改传播到ControlB的最简单/最简洁的方法是什么。

    感谢您的帮助!

    亨利

    的Xaml: -

    <UserControl x:Class="VisualStateChangePropagation.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:VisualStateChangePropagation"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <Grid.Resources>
    
                <SolidColorBrush x:Name="Fill_Bg_Red" Color="Red"/>
                <SolidColorBrush x:Name="Fill_Bg_Blue" Color="Blue"/>
    
                <ControlTemplate x:Name="templateA" TargetType="Control">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="Common">
                                <VisualState x:Name="StateOn">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="m_rect"
                                                                       Storyboard.TargetProperty="(Rectangle.Fill)">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource Fill_Bg_Red}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="StateOff"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Rectangle x:Name="m_rect" Fill="{StaticResource Fill_Bg_Blue}"/>
                    </Grid>
                </ControlTemplate>
    
                <ControlTemplate x:Name="templateB" TargetType="Control">
                    <local:ControlB Template="{StaticResource templateA}"/>
                </ControlTemplate>
    
            </Grid.Resources>
            <local:ControlA x:Name="m_control1" Template="{StaticResource templateA}" Grid.Column="0"/>
            <Button Click="Button_Click" Grid.Column="1" Content="swap"/>
            <local:ControlA x:Name="m_control2" Template="{StaticResource templateB}" Grid.Column="2"/>
        </Grid>
    </UserControl>
    
    代码背后的代码:

    public class ControlA : Control
    {
        public void ToggleState()
        {
            m_isSet = !m_isSet;
            UpdateVisualState();
        }
    
        private void UpdateVisualState()
        {
            string targetState = m_isSet ? "StateOn" : "StateOff";
            VisualStateManager.GoToState(this, targetState, false);
        }
    
        private bool m_isSet = false;
    }
    
    public class ControlB : Control
    {
    
    }
    

1 个答案:

答案 0 :(得分:0)

首先,ControlA和ControlB都应具有IsSet的依赖属性。

    public bool IsSet
    {
        get { return (bool)GetValue(IsSetProperty); }
        set { SetValue(IsSetProperty, value); }
    }

    public static readonly DependencyProperty IsSetProperty =
            DependencyProperty.Register(
                    "IsSet",
                    typeof(bool),
                    typeof(ControlA),  //Change in ControlB
                    new PropertyMetadata(false, OnIsSetPropertyChanged));

    private static void OnIsSetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Control source = d as Control;
         string newState = (bool)e.NewValue ? "StateOn" : "StateOff";
         VisualStateManager.GotoState(source, newState, true);
    }

与你的直觉相反,视觉状态根本不会传播。这些州只对它们直接附加的控制有意义。但是,将这个依赖项属性添加到两个控件后,您现在可以通过模板绑定传播属性值: -

        <ControlTemplate x:Name="templateB" TargetType="Control">
            <local:ControlB Template="{StaticResource templateA}" IsSet="{TemplateBinding IsSet}" />
        </ControlTemplate>

对于原始ControlA代码,不再需要m_isSet字段: -

public void ToggleState()
{
    IsSet = !IsSet;
}