1

VisualStateGroup私が理解していない sについての基本的なことがあります。私が読んだすべてのことから、それらが直交していると信じるようになりました。つまり、あるグループの状態が変化しても、他のグループには影響しません。実際、そうでないと意味がありません。

ただし、私が遭遇したいくつかの奇妙な動作を理解しようとして、あるグループの状態変化が別のグループのアニメーションをトリガーできることを示す簡単な例をまとめました。私はこれがどのようにできるかを理解しようとしています。

私が望むのは、たとえば、フォーカスがあるかどうか、またはマウスがその上にあるかどうかに関係なく、ToggleButtonトグル ( ) されたときに 1 つの外観を持つベースのコントロールだけです。IsChecked == true

まず、カスタム グループ内のカスタム状態間を遷移する非常に単純なコントロールがあります。

using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

[TemplateVisualState(Name = normalState, GroupName = activationGroupName)]
[TemplateVisualState(Name = hoverState, GroupName = activationGroupName)]
[TemplateVisualState(Name = activatedState, GroupName = activationGroupName)]
public class CustomControl : ToggleButton
{
    private const string activationGroupName = "Activation";
    private const string normalState = "Normal";
    private const string hoverState = "Hover";
    private const string activatedState = "Activated";

    public CustomControl()
    {
        this.DefaultStyleKey = typeof(CustomControl);

        this.Checked += delegate
        {
            this.UpdateStates();
        };
        this.Unchecked += delegate
        {
            this.UpdateStates();
        };
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        this.UpdateStates();
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        this.UpdateStates();
    }

    protected override void OnMouseLeave(MouseEventArgs e)
    {
        base.OnMouseLeave(e);
        this.UpdateStates();
    }

    private void UpdateStates()
    {
        var state = normalState;

        if (this.IsChecked.HasValue && this.IsChecked.Value)
        {
            state = activatedState;
        }
        else if (this.IsMouseOver)
        {
            state = hoverState;
        }

        VisualStateManager.GoToState(this, state, true);
    }
}

次に、現在の状態に基づいて背景色を変更するこのコントロールのテンプレートがあります。

<Style TargetType="local:CustomControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:CustomControl">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="Activation">
                            <VisualStateGroup.Transitions>
                                <VisualTransition To="Normal" GeneratedDuration="00:00:0.2"/>
                            </VisualStateGroup.Transitions>

                            <VisualState x:Name="Normal"/>

                            <VisualState x:Name="Hover">
                                <Storyboard>
                                    <ColorAnimation Duration="00:00:0.2" To="Red" Storyboard.TargetName="grid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"/>
                                </Storyboard>
                            </VisualState>

                            <VisualState x:Name="Activated">
                                <Storyboard>
                                    <ColorAnimation Duration="00:00:0.2" To="Blue" Storyboard.TargetName="grid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <Grid x:Name="grid" Background="White">
                        <TextBlock>ToggleButton that should be white normally, red on hover, and blue when checked</TextBlock>
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ほとんどの場合は機能しますが、コントロールがフォーカスを失うと、通常の状態に戻ります。

コントロールでフォーカスの変更を明示的に処理し、状態の更新を実行することで、これを回避できます。

public CustomControl()
{
    this.DefaultStyleKey = typeof(CustomControl);

    this.Checked += delegate
    {
        this.UpdateStates();
    };
    this.Unchecked += delegate
    {
        this.UpdateStates();
    };

    // explicitly handle focus changes
    this.GotFocus += delegate
    {
        this.UpdateStates();
    };
    this.LostFocus += delegate
    {
        this.UpdateStates();
    };
}

しかし、なぜ私がこれをしなければならないのか、私には意味がありません。

1 つの状態が変化するとVisualStateGroup、別のアニメーションで定義されたアニメーションが実行されるのはなぜですか? そして、私が述べた目標を達成するための最も簡単で最も正しい方法は何ですか?

ありがとう

4

1 に答える 1

2

GotoStateメソッドがどのグループに属しているかについての修飾なしに、州名を単純に取得する方法に注意してください。グループは、コントロールが一度に保持できる状態のセット (グループごとに 1 つの状態) を分離しますが、状態名はマネージャーのすべての状態で一意であることが期待されます。

ToggleButton派生元の には、クラスに関連付けられた次の属性があることにも注意してください。

[TemplateVisualStateAttribute(Name = "Normal", GroupName = "CommonStates")]

これは、継承したロジックがある時点でGotoState「通常」の状態で呼び出されることを示しています。通常、コントロールには(あなたが持っているように)1つのメソッドしかなく、状態のいずれかが変更された可能性がある任意UpdateStatesの時点で呼び出されます。この関数は、各グループの 1 つの状態名で複数回呼び出されます。したがって、コントロールがフォーカスを失った時点で、「Unfocused」状態を設定するための呼び出しが行われますが、それに伴い、「Normal」および「Checked」または「Unchecked」でも呼び出されます。GotoStateToggleButtonGotoState

これで、"Unfocused"、"Checked" の状態が存在しない独自のテンプレートができたので、GotoStatefromへの呼び出しToggleButtonは何もしません。ただし、「通常」があります。ToggleButtonVSM には、「Normal」の使用がデフォルト テンプレートの「CommonStates」グループから選択することを意図していることを知る方法がありません。代わりにVisualState、この場合は「Activation」グループにある「Normal」という名前の を見つけるだけです。したがって、既存の「アクティブ」の状態は「通常」に置き換えられます。

「通常」を「何とか」に変更すると、期待どおりに機能します。

(グループ名は、 に存在するにもかかわらず、実際にはあまり機能しないことを覚えておくと役立ちます。TemplateVisualStateAttribute私が考えることができる唯一の用途は、Blend UI です)。

于 2010-07-13T12:52:22.730 に答える