3

我正在向滑块添加附加行为,当拇指被拖动并保持在特定区域上时,这将导致它滚动一些内容。(不能使用简单的 IsMouseOver 触发器,因为 Slider Thumb 具有 MouseCapture。)

该行为具有 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 挂接到两个 Rectangle 中,以检测鼠标何时进入它们。

因此,有问题的矩形也在 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>

我遇到的问题是将这些矩形绑定到附加的 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”出现两次,但事实并非如此,并且我得到与您相同的错误:

System.Windows.Data 错误:4:找不到与引用“ElementName = theText”绑定的源。绑定表达式:路径=文本;数据项=空;目标元素是 'Button' (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().

尽管它可能看起来更复杂,但它有一个很好的好处:标记会更简单。使用 Blend 的设计师不必记住连接那些复杂的触发器,他们只需正确命名控件即可。

PART_ 前缀的使用是 WPF 约定,通常与TemplatePart属性一起使用。TextBox 就是一个例子。当您覆盖 a 的模板时TextBox它不会起作用,直到您添加一个名为 PART_ContentHost.

更新:我刚刚在这里写了关于模板部分的博客:http: //www.paulstovell.com/wpf-part-names

于 2011-04-03T07:06:11.797 回答