附加行为绑定到 controltemplate 中的元素
我正在向滑块添加附加行为,这将导致当拇指被拖动并保持在特定区域上时滚动一些内容。 (不能使用简单的 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 挂接到两个矩形中,以检测鼠标何时进入它们。
有问题的矩形也在滑块的控制模板中定义:
<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>
我知道当矩形按预期填充红色时,此触发器将被触发。 谁能从这些片段中发现我做错了什么?
提前致谢。
抢
I am adding an attached behaviour to a slider which will cause it to scroll some content when the thumb is dragged and held over a specific region. (Can't use a straightforward IsMouseOver trigger as the Slider Thumb has MouseCapture.)
The behaviour has 3 properties:
#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
The IsScrollHoverProperty is being set to true when the user drags the slider, this is all done in the Slider's ControlTemplates.Triggers, and works correctly.
When it's set to true the callback is going to hook PreviewMouseEnterHandlers into the two Rectangles to detect when the mouse enters them.
The Rectangles in question are also defined in the Slider's controltemplate thusly:
<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>
The problem I have is binding these Rectangles to the attached ScrollRightRect and ScrollLeftRect Properties. I have tried a few things and suspect I have made a stupid binding error or am trying to do something not allowed. I am currently binding them in the controltemplate.triggers as follows:
<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>
I know this Trigger is being tripped as the rectangles fill Red as expected.
Can anyone spot what I'm doing wrong from these snippets?
Thanks in advance.
Rob
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,我们确认一下你没有做错什么,而且问题与附加行为无关。
当我将鼠标悬停在按钮上时,此代码片段应该会导致“Hello”出现两次,但事实并非如此,并且我得到了与您相同的错误:
这是可以解释的 - 一旦在
Button
上设置绑定,它将无法找到名为“theText”的控件,因为 Button位于不同的 NameScope 中。替代方案
某些 WPF 控件需要执行与您类似的操作 - 它们假设树中存在与它们交互的特定控件。但他们不使用属性 - 他们使用名称。
首先为控件命名 - 约定是使用“PART_”前缀:
现在,当设置
IsScrollHover
时,将这样的代码放入回调中:请注意,这取决于
IsScrollHost
何时设置code> 属性已设置,模板可能尚未准备好。在这种情况下,您可能需要订阅Loaded
或类似事件,然后调用ApplyTemplate()
。虽然它可能看起来更复杂,但它有一个很好的好处:标记会更简单。使用 Blend 的设计人员不必记住连接那些复杂的触发器,他们只需正确命名控件即可。
PART_ 前缀的使用是 WPF 约定,通常与 TemplatePart 属性。文本框就是一个例子。当您覆盖
TextBox
的模板时,它不会'直到您添加名为PART_ContentHost
的控件为止,该函数才会起作用。更新:我刚刚在此处发布了有关模板部分的博客:http://www.paulstovell.com/ wpf-部分名称
First, let's confirm you're not doing anything wrong, and the problem has nothing to do with the attached behaviors.
This snippet should cause "Hello" to appear twice when I mouse over the button, but it doesn't, and I get the same error as you:
This is explainable - once the binding is set on the
Button
, it won't be able to find a control named 'theText', because the Button lives in a different NameScope.An alternative
Some WPF controls need to do something similar to you - they assume that a specific control exists in the tree that they will interact with. But they don't use properties - they use names.
Start by giving the controls a name - the convention is to use "PART_" prefix:
Now put code like this in your callback when
IsScrollHover
is set:Note that depending on when the
IsScrollHost
property is set, the template might not be ready yet. In that case, you might want to subscribe to theLoaded
or similar event, and then callApplyTemplate()
.Although it might seem more complicated, it has one nice benefit: the markup will be simpler. A designer using Blend won't have to remember to wire up those complicated triggers, they just have to name the controls correctly.
The use of the PART_ prefix is a WPF convention, and normally used along with the TemplatePart attribute. An example of this is the TextBox. When you override the template of a
TextBox
, it won't function until you add a control namedPART_ContentHost
.Update: I just blogged about template parts here: http://www.paulstovell.com/wpf-part-names