3

つまみをドラッグして特定の領域に保持すると、一部のコンテンツをスクロールさせる動作をスライダーに追加しています。(Slider Thumb には MouseCapture があるため、単純な IsMouseOver トリガーは使用できません。)

動作には 3 つのプロパティがあります。

    #region IsScrollHoverProperty
    public static readonly DependencyProperty IsScrollHoverProperty = DependencyProperty.RegisterAttached(
                                                "IsScrollHover",
                                                typeof(Boolean),
                                                typeof(ScrollHoverAreaBehaviour),
                                                new UIPropertyMetadata(false));
    #endregion

    #region ScrollLeftRectProperty
    public static readonly DependencyProperty ScrollLeftRectProperty = DependencyProperty.RegisterAttached(
                                                "ScrollLeftRect",
                                                typeof(Rectangle),
                                                typeof(ScrollHoverAreaBehaviour),
                                                new UIPropertyMetadata(null));
    #endregion

    #region ScrollRightRectProperty
    public static readonly DependencyProperty ScrollRightRectProperty = DependencyProperty.RegisterAttached(
                                                "ScrollRightRect",
                                                typeof(Rectangle),
                                                typeof(ScrollHoverAreaBehaviour),
                                                new UIPropertyMetadata(null));
    #endregion

ユーザーがスライダーをドラッグすると、IsScrollHoverProperty が true に設定されます。これはすべて Slider の ControlTemplates.Triggers で行われ、正しく機能します。

true に設定すると、コールバックは PreviewMouseEnterHandlers を 2 つの Rectangles にフックして、マウスがそれらに入ったときを検出します。

問題の Rectangles は、Slider の controltemplate でも次のように定義されています。

        <StackPanel Grid.Row="0" Grid.RowSpan="3" HorizontalAlignment="Left" Orientation="Horizontal">
            <Rectangle  Width="40" Fill="#AAAAAAAA" Name="ScrollLeftRect"/>

            </StackPanel>
        <StackPanel Grid.Row="0" Grid.RowSpan="3" HorizontalAlignment="Right" Orientation="Horizontal">
            <Rectangle  Width="40" Fill="#AAAAAAAA" Name="ScrollRightRect"/>
         </StackPanel>

私が抱えている問題は、これらの Rectangles を添付の ScrollRightRect および ScrollLeftRect プロパティにバインドすることです。私はいくつかのことを試してみましたが、ばかげたバインド エラーを起こしたか、許可されていないことをしようとしていると思われます。現在、次のように controltemplate.triggers にバインドしています。

        <Trigger Property="local:ScrollHoverAreaBehaviour.IsScrollHover" Value="False">

            <Setter Property="local:ScrollHoverAreaBehaviour.ScrollLeftRect" Value="{Binding ElementName=ScrollLeftRect}"/>
            <Setter Property="local:ScrollHoverAreaBehaviour.ScrollRightRect" Value="{Binding ElementName=ScrollRightRect}"/>

            <Setter TargetName="ScrollLeftRect" Property="Fill" Value="Red"/>
            <Setter TargetName="ScrollRightRect" Property="Fill" Value="Red"/>
        </Trigger>

長方形が予想どおり赤で塗りつぶされているため、このトリガーが作動していることがわかります。これらのスニペットから私が間違っていることを誰でも見つけることができますか?

前もって感謝します。

ロブ

4

1 に答える 1

13

まず、あなたが何も悪いことをしていないことを確認しましょう。問題は添付された動作とは何の関係もありません。

<Button>
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Border Background="Yellow">
                <StackPanel>
                    <TextBlock x:Name="theText" Text="Hello" />
                    <ContentPresenter />
                </StackPanel>
            </Border>

            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Content" Value="{Binding ElementName=theText, Path=Text}" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

このスニペットにより、ボタンにマウスを合わせると「Hello」が2回表示されるはずですが、そうではなく、あなたと同じエラーが発生します。

System.Windows.Data エラー: 4 : 参照 'ElementName=theText' を含むバインディングのソースが見つかりません。BindingExpression: パス = テキスト; DataItem=null; ターゲット要素は 'ボタン' (Name=''); ターゲット プロパティは「コンテンツ」(タイプ「オブジェクト」)

これは説明がつきます - バインディングが に設定されるとButton、「theText」という名前のコントロールを見つけることができなくなります。これは、Button が別のNameScopeに存在するためです。

代替案

一部の WPF コントロールは、あなたと同様のことを行う必要があります。それらは、対話する特定のコントロールがツリーに存在することを前提としています。しかし、それらはプロパティを使用せず、名前を使用します。

コントロールに名前を付けることから始めます。規則では、「PART_」プレフィックスを使用します。

<Rectangle ... Name="PART_ScrollLeftRect" />

IsScrollHoverが設定されている場合、コールバックに次のようなコードを追加します。

private static void IsScrollHoverSetCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var target = (Slider) d;
    if ((bool)e.NewValue == false)
        return;

    target.ApplyTemplate();
    var leftRectangle = target.Template.FindName("PART_ScrollLeftRect", target);
    var rightRectangle = target.Template.FindName("PART_ScrollRightRect", target);

    // Do things with the rectangles
}

IsScrollHostプロパティがいつ設定されるかによっては、テンプレートがまだ準備できていない可能性があることに注意してください。その場合、Loadedまたは同様のイベントにサブスクライブしてから、 を呼び出すことができますApplyTemplate()

より複雑に見えるかもしれませんが、1 つの利点があります。それは、マークアップがより単純になるということです。Blend を使用するデザイナーは、これらの複雑なトリガーを接続することを覚えておく必要はありません。コントロールに正しい名前を付けるだけで済みます。

PART_ プレフィックスの使用は WPF 規則であり、通常はTemplatePart属性と共に使用されます。この例は TextBox です。のテンプレートをオーバーライドすると、TextBoxという名前のコントロールを追加するまで機能しません PART_ContentHost

更新: ここでテンプレート パーツについてブログを書きました: http://www.paulstovell.com/wpf-part-names

于 2011-04-03T07:06:11.797 に答える