如何在Path.Data中使用TemplateBinding?
How to use TemplateBinding in Path.Data?
如何将 Path.Data
内的 属性 绑定到 TemplateBinding
?我注意到在以下示例中,属性 SegmentColor
和 StrokeThickness
已正确设置和更新,但 属性 TargetPoint
未正确设置和更新。进一步的测试似乎证实该问题似乎与 属性 嵌套在 Path.Data
的元素中有关。以下代码试图简化我在为自定义控件创建模板时所面临的上下文。
C#:
public class TestProgressBar : ProgressBar
{
public Brush SegmentColor
{
get { return (Brush)GetValue(SegmentColorProperty); }
set { SetValue(SegmentColorProperty, value); }
}
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
public Point TargetPoint
{
get { return (Point)GetValue(TargetPointProperty); }
set { SetValue(TargetPointProperty, value); }
}
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(nameof(StrokeThickness), typeof(double), typeof(TestProgressBar), new PropertyMetadata());
public static readonly DependencyProperty SegmentColorProperty =
DependencyProperty.Register(nameof(SegmentColor), typeof(Brush), typeof(TestProgressBar), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
public static readonly DependencyProperty TargetPointProperty =
DependencyProperty.Register(nameof(TargetPoint), typeof(Point), typeof(TestProgressBar), new PropertyMetadata());
}
Xaml:
<c:TestProgressBar StrokeThickness="15"
TargetPoint="100,0">
<c:TestProgressBar.Style>
<Style TargetType="{x:Type c:TestProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:TestProgressBar}">
<Grid>
<Path
Stroke="{TemplateBinding SegmentColor}"
StrokeThickness="{TemplateBinding StrokeThickness}"
Width="100" Height="100">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="{TemplateBinding TargetPoint}"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</c:TestProgressBar.Style>
</c:TestProgressBar>
似乎是在 Path.Data 中使用 TemplateBindings 导致了这个问题。用 TemplatedParent Binding 替换它可以解决问题:
<LineSegment Point="{Binding TargetPoint, RelativeSource={RelativeSource TemplatedParent}}"/>
虽然我不能完全解释这是为什么。在我的原始代码中,我使用的是只读依赖属性,因此该问题不能与 TwoWay 绑定问题相关联(因为我很难将其与 TemplateBinding 联系起来)。
我知道使用 TemplatedParent 的绑定是 runtime-evaluated,而不是使用 TemplateBinding 的 compile-time,所以也许沿着这些思路修复了绑定。
问题是关于 TemplateBinding
的一个鲜为人知的细节,它们 do not work on properties Freezable
s. In fact, a LineSegment
间接派生自 Freezable
,如您在其继承层次结构中所见。
Object -> DispatcherObject -> DependencyObject -> Freezable -> Animatable -> PathSegment -> LineSegment
然而,Path
没有,这就是为什么 TemplateBinding
对其属性起作用的原因。由于模板绑定只是 Binding
的优化 但受限 版本,您始终可以 use its binding syntax equivalent 没有任何限制并且也适用于 Freezable
s.
<LineSegment Point="{Binding TargetPoint, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
注意,这里 Mode
设置为 OneWay
,以指出 TemplateBinding
始终是 one-way,这相当于 Binding
,但绑定更强大,支持任何绑定模式。
I am using readonly dependency properties, so the issue can't be linked to TwoWay binding problems (as I've hard can be the case with TemplateBinding).
依赖项 属性 声明必须是 read-only,但这不会使依赖项 属性 read-only 本身,这是通过声明依赖项 [=46] 来完成的=] 键并使用 RegisterReadOnly
方法。
如何将 Path.Data
内的 属性 绑定到 TemplateBinding
?我注意到在以下示例中,属性 SegmentColor
和 StrokeThickness
已正确设置和更新,但 属性 TargetPoint
未正确设置和更新。进一步的测试似乎证实该问题似乎与 属性 嵌套在 Path.Data
的元素中有关。以下代码试图简化我在为自定义控件创建模板时所面临的上下文。
C#:
public class TestProgressBar : ProgressBar
{
public Brush SegmentColor
{
get { return (Brush)GetValue(SegmentColorProperty); }
set { SetValue(SegmentColorProperty, value); }
}
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
public Point TargetPoint
{
get { return (Point)GetValue(TargetPointProperty); }
set { SetValue(TargetPointProperty, value); }
}
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(nameof(StrokeThickness), typeof(double), typeof(TestProgressBar), new PropertyMetadata());
public static readonly DependencyProperty SegmentColorProperty =
DependencyProperty.Register(nameof(SegmentColor), typeof(Brush), typeof(TestProgressBar), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
public static readonly DependencyProperty TargetPointProperty =
DependencyProperty.Register(nameof(TargetPoint), typeof(Point), typeof(TestProgressBar), new PropertyMetadata());
}
Xaml:
<c:TestProgressBar StrokeThickness="15"
TargetPoint="100,0">
<c:TestProgressBar.Style>
<Style TargetType="{x:Type c:TestProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:TestProgressBar}">
<Grid>
<Path
Stroke="{TemplateBinding SegmentColor}"
StrokeThickness="{TemplateBinding StrokeThickness}"
Width="100" Height="100">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="{TemplateBinding TargetPoint}"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</c:TestProgressBar.Style>
</c:TestProgressBar>
似乎是在 Path.Data 中使用 TemplateBindings 导致了这个问题。用 TemplatedParent Binding 替换它可以解决问题:
<LineSegment Point="{Binding TargetPoint, RelativeSource={RelativeSource TemplatedParent}}"/>
虽然我不能完全解释这是为什么。在我的原始代码中,我使用的是只读依赖属性,因此该问题不能与 TwoWay 绑定问题相关联(因为我很难将其与 TemplateBinding 联系起来)。
我知道使用 TemplatedParent 的绑定是 runtime-evaluated,而不是使用 TemplateBinding 的 compile-time,所以也许沿着这些思路修复了绑定。
问题是关于 TemplateBinding
的一个鲜为人知的细节,它们 do not work on properties Freezable
s. In fact, a LineSegment
间接派生自 Freezable
,如您在其继承层次结构中所见。
Object -> DispatcherObject -> DependencyObject -> Freezable -> Animatable -> PathSegment -> LineSegment
然而,Path
没有,这就是为什么 TemplateBinding
对其属性起作用的原因。由于模板绑定只是 Binding
的优化 但受限 版本,您始终可以 use its binding syntax equivalent 没有任何限制并且也适用于 Freezable
s.
<LineSegment Point="{Binding TargetPoint, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
注意,这里 Mode
设置为 OneWay
,以指出 TemplateBinding
始终是 one-way,这相当于 Binding
,但绑定更强大,支持任何绑定模式。
I am using readonly dependency properties, so the issue can't be linked to TwoWay binding problems (as I've hard can be the case with TemplateBinding).
依赖项 属性 声明必须是 read-only,但这不会使依赖项 属性 read-only 本身,这是通过声明依赖项 [=46] 来完成的=] 键并使用 RegisterReadOnly
方法。