附加行为绑定到controltemplate中的元素

时间:2011-04-02 18:30:56

标签: wpf binding controltemplate attachedbehaviors

我正在向滑块添加附加行为,这会导致当拖动拇指并将其保持在特定区域时滚动某些内容。 (不能使用简单的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>

我知道这个触发器正在跳闸,因为矩形按预期填充红色。 谁能从这些片段中发现我做错了什么?

提前致谢。

罗布

1 个答案:

答案 0 :(得分: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'的绑定源。 BindingExpression:路径=文本;的DataItem = NULL; target元素是'Button'(Name =''); target属性是'Content'(类型'Object')

这是可以解释的 - 一旦在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。当您覆盖TextBoxit won't function until you add a control named PART_ContentHost

的模板时

更新:我刚刚在此处发布了有关模板部分的博文:http://www.paulstovell.com/wpf-part-names