应用
您好,我正在为WPF应用程序动态添加自定义控件。该控件是一个自定义滑块。我在XAML文件中创建了一个ControlTemplate,我想将其用作这些动态创建的控件的模板。我目前正在使用以下方法应用模板:
newControl.Template = (ControlTemplate)parent.Resources["nameOfTheControlTemplate"];
目前可以正常工作(即编译,运行和应用模板)。
模板如下所示:(抱歉,文字墙)
<ControlTemplate x:Key="errorRangeSliderRight" TargetType="{x:Type Slider}">
<Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.Thumb>
<Thumb x:Name="Thumb" HorizontalContentAlignment="Right" Width="7">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Path x:Name="nameOfPath" Stroke="Black" StrokeThickness="0" Fill="Red">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<PathGeometry>
<PathGeometry.Figures>
<PathFigure IsClosed="True" StartPoint="7,150">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="5,150" />
<LineSegment Point="5,0" />
<LineSegment Point="7,0" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<PathFigure IsClosed="True" StartPoint="0,75">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="7,70" />
<LineSegment Point="7,80" />
<LineSegment Point="0,75" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
</ControlTemplate>
推理:
我选择在XAML中定义控件模板而不是使用FrameworkElementFactory使用数百万行代码动态创建模板的原因是因为它更容易,更清晰,更易于维护/读取。
我想要的是什么:
我想在ControlTemplate中对此控件模板(仅限Path对象的填充颜色)进行轻微更改。如果可能的话,我想获得对ControlTemplate对象的引用。
我尝试了什么:
我尝试在模板上调用FindName(“nameOfPath”),它返回一个空对象。
Object o = newControl.Template.FindName("nameOfPath",newControl);
我尝试使用大量的FrameworkElementFactory实例创建ContentTemlpate并以这种方式构建ControlTemplate,这是不成功的(ControlTemplate对象非常复杂并且有许多子元素)。
答案 0 :(得分:2)
我会强烈阻止在运行时以这种方式篡改模板(或者更确切地说是从模板实例化的控件),这是糟糕的设计。
您要做的是使用属性。例如,将Path.Fill
绑定到Foreground
?如果您认为这在语义上不够合适,那么最好继承Slider
并创建所需的属性,而不是在运行时弄乱模板。
在您的情况下,您拥有嵌套模板,因此您必须转发TemplateBinding
或使用RelativeSource
绑定执行某些操作,这取决于您。例如使用转发:
<!-- ... -->
<Thumb x:Name="Thumb" HorizontalContentAlignment="Right" Width="7"
Background="{TemplateBinding Foreground}">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Path x:Name="nameOfPath" Stroke="Black" StrokeThickness="0"
Fill="{TemplateBinding Background}">
这会将Path.Fill
绑定到Thumb.Background
(它是),Thumb.Background
绑定到Slider.Foreground
,这似乎也是合理的。现在你只需要在Foreground
上设置Slider
来设置路径的Fill
,不错,不是吗?
顺便说一句:你应该保留你想要抽象的想法。
我想对此控件模板稍作修改......
事实上,这不是你想要的,而是你认为需要的结果才能得到你想要的东西。您将真正想要的内容放入括号中:“[更改为Path对象的填充颜色”
答案 1 :(得分:1)
您可能不希望在代码隐藏中更改模板,因为这会改变使用该模板的每个控件。
相反,一旦您的控件已经渲染,您可以导航它的可视树以找到需要更改的特定元素并更改它们。 Loaded
事件在处理完所有Render
事件后运行,因此您应该能够在任何Loaded
事件期间调整控件模板中的控件。
我写了一组VisualTreeHelpers,我经常使用它来查找WPF视觉树中的控件。它们可以像这样使用:
Path path = VisualTreeHelpers.FindChild<Path>(newControl, "nameOfPath");