1

我目前面临一种情况,我不确定什么是最好的处理方式。

设想:

  1. ControlA 有 2 两个自定义视觉状态,我们称它们为“StateOn”和“StateOff”。
  2. 我现在在 ControlA 上应用一个模板,我们称之为“templateA”。
  3. “templateA”下面有一个 ControlB 类型的控件(他不知道 StateOn/Off)。
  4. ControlB 有一个 Template 来处理 ControlA 的视觉状态变化,即 StateOn 和 StateOff。

问题:
ControlB 没有收到对 ControlA 触发的 VisualStates 的更改,因此不会发生视觉更改。

我认为问题与作为控件(ControlB)的根元素有关,它不会在所需状态下触发 gotostate。但是,我想知道将 ControlA 的视觉状态更改传播到 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
{

}
4

1 回答 1

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;
}
于 2010-08-19T21:19:43.353 回答