3

Silverlight の TemplatedControl を WPF に移植しましたが、ほとんど同じように動作しますが、アニメーションが機能しなくなりました。

呼び出すVisualStateManager.GoToState()とfalseが返されます。これを手動で強制しようとして、他の誰かの推奨に従い、視覚状態グループを名前で検索し、ストーリーボードを強制的に実行しました。

        foreach (VisualStateGroup vsg in VisualStateManager.GetVisualStateGroups(part_LayoutRoot))
        {
            VisualState vs = vsg.States.Cast<VisualState>().FirstOrDefault(o => o.Name == visualState);

            if (vs == null)
                throw new ApplicationException("No visual state found with name: " + visualState);

            vs.Storyboard.Begin();
            break;
        }

No applicable name scope exists to resolve the name 'PART_MyPart' ただし、これを呼び出すと例外がスローされますStoryboard.Begin()

さらに調査すると、VisualStateManager、ビジュアル ステート、およびストーリーボードはすべて、呼び出されたときに null を返すNameScope.GetNameScope()ため、コードでも手動で設定しようとしました。

        var nameScope = NameScope.GetNameScope(vs.Storyboard);
        if (nameScope == null)
        {
            nameScope = NameScope.GetNameScope(part_LayoutRoot);
            NameScope.SetNameScope(vsg, nameScope);
            NameScope.SetNameScope(vs, nameScope);
            NameScope.SetNameScope(vs.Storyboard, nameScope);
        }

ただし、例外は発生し続けており、私の人生では理由を考えることができません。これは、Silverlight で期待どおりに機能します。

NameScope に関して Silverlight と WPF の間で動作が異なる理由を誰かが明らかにすることはできますか?

ありがとう

4

2 に答える 2

1

コントロール テンプレート内の名前付き要素を取得し、「該当する名前のスコープがない」問題を解決するstoryboard.Begin(_retrievedElement)だけでなく、呼び出します。storyboard.Begin()その場合、渡されたフレームワーク要素の名前スコープがストーリーボードに適用されます。このメソッドのさまざまなオーバーロードの詳細については、http://msdn.microsoft.com/en-us/library/system.windows.media.animation.storyboard.begin.aspxを参照してください。

残念ながら、Visual States Manager があなたのコントロールで機能しない理由を再構築することはできません。

更新: コントロール テンプレートが Silverlight では機能するのに、WPF では機能しない理由を理解できたかもしれません。詳細は次の回答で。

于 2013-04-19T16:45:47.710 に答える
0

また、移植したコントロール テンプレートが機能しない理由もわかるかもしれません。WPF では、ビジュアル状態内のストーリーボードでバインディングを使用することはできません。次のテンプレートを検討してください。

<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
        <Border x:Name="ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Background="White" BorderBrush="#FFB0B0B0">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:0.3"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                            To="{Binding (Border.BorderBrush).(SolidColorBrush.Color), ElementName=ButtonBorder}"
                            Duration="0"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed"/>
                <VisualState x:Name="Disabled"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Rectangle x:Name="rectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#00000000"/>
            <ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>

</ControlTemplate>

重要な部分は、要素バインディングが使用されるビジュアル ステート「MouseOver」です。このコードは、Silverlight で完全に正常に実行されますが、WPF では、データ バインディング エンジンは、「ButtonBorder」という名前の要素が見つからないことを通知します (以下を参照)。 [出力] ウィンドウでデータ バインディング エラーをトレースします)。これは、以前の回答で述べた名前空間の問題に関係しています。この問題の回避策は次のようになります。

<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
        <Border x:Name="ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Background="White" BorderBrush="#FFB0B0B0">
            <Border.Resources>
            <Storyboard x:Key="MouseOverStoryboard">
                <ColorAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                            To="{Binding (Border.BorderBrush).(SolidColorBrush.Color), ElementName=ButtonBorder}"
                            Duration="0"/>
            </Storyboard>
        </Border.Resources>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:0.3"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver" Storyboard="{StaticResource MouseOverStoryboard}">

                </VisualState>
                <VisualState x:Name="Pressed"/>
                <VisualState x:Name="Disabled"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Rectangle x:Name="rectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#00000000"/>
            <ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>

</ControlTemplate>

現在、ストーリーボードはルート テンプレート要素の Resource プロパティに追加されているため、名前のスコープが適合しているように見えます。表示状態では、静的リソース マークアップ拡張機能を使用してストーリーボードを参照するだけです。この XAML は Silverlight では実行されないため、両方のプロジェクトでファイルを共有できないことに注意してください。また、Blend はこのマークアップを処理できないため、手動で記述する必要があります。

お役に立てれば。

于 2013-04-21T07:56:09.267 に答える