从代码隐藏更改 ControlTemplate
应用程序:
您好,我正在向 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 实例创建 ContentTemplate 并以这种方式构建 ControlTemplate,但这是不成功的( ControlTemplate 对象非常复杂并且具有许多子元素)。
Application:
Hello, I am dynamically adding custom controls to a WPF application. The control is a custom slider. I have created a ControlTemplate in the XAML file which I want to use as the template for these dynamically created controls. I am currently applying the template by using:
newControl.Template = (ControlTemplate)parent.Resources["nameOfTheControlTemplate"];
This currently works OK (i.e. compiles, runs, and applys the template).
The template looks like this: ( Sorry for wall of text )
<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>
Reasoning:
The reason why I chose to define the control template in the XAML rather than dynamically create a template using millions of lines of code using FrameworkElementFactory's is because it is easier, cleaner, and easier to maintain/read.
What I want:
I would like to make slight alterations to this control template ( only the Fill color of a Path object ) within the ControlTemplate. If it is possible I would like to get a reference to the ControlTemplate object.
What I have tried:
I have tried calling a FindName("nameOfPath") on the Template, it returns a null object.
Object o = newControl.Template.FindName("nameOfPath",newControl);
I have tried creating the ContentTemlpate using lots of FrameworkElementFactory instances and building the ControlTemplate that way, this was unsuccessful ( the ControlTemplate object is quite complex and has many child elements).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我强烈不鼓励在运行时以这种方式篡改模板(或者更确切地说从模板实例化的控件),这是糟糕的设计。
相反,您想要做的是使用属性。例如将
Path.Fill
绑定到Foreground
?如果您认为这在语义上不够合适,您最好从Slider
继承并创建您需要的属性,而不是在运行时弄乱模板。在您的情况下,您有嵌套模板,因此您必须转发
TemplateBinding
或使用RelativeSource
绑定执行某些操作,这取决于您。例如使用转发:这会将
Path.Fill
绑定到Thumb.Background
(它就是),并且将Thumb.Background
绑定到Slider.Foreground
这看起来也很合理。现在你只需要设置Slider
上的Foreground
来设置路径的Fill
,很好,不是吗?顺便说一句:你应该保持你想要的想法抽象。
这实际上不是您想要的,而是您认为需要得到您想要的结果。您将真正想要的内容放入括号中:“[更改]路径对象的填充颜色”
I would strongly discourage tampering with templates (or rather controls instantiated from templates) at runtime in this way, it is bad design.
What you want to do instead is using properties. For example bind the
Path.Fill
to theForeground
? If you think that is not semantically fitting enough you would be better off inheriting fromSlider
and creating the property you need rather than messing with the template at runtime.In your case you have nested templates so you have to forward the
TemplateBinding
or do something with aRelativeSource
binding, it is up to you. e.g. using forwarding:This binds the
Path.Fill
to theThumb.Background
(which it is) and theThumb.Background
is bound to theSlider.Foreground
which seems reasonable as well. Now you just need to set theForeground
on theSlider
to set theFill
of the path, nice, is it not?As an aside: You should keep the idea of what you want abstract.
That is in fact not what you want but a consequence that you think is needed to get you what you want. You put what you really want into parenthesis: "[alterations to] the Fill color of a Path object"
您可能不想在代码隐藏中更改模板,因为这会更改使用该模板的每个控件。
相反,一旦渲染了控件,您就可以导航它的可视化树以查找需要更改的特定元素并更改它们。
Loaded
事件在处理所有Render
事件后运行,因此您应该能够在任何Loaded
事件期间调整控件模板中的控件。我写了一组 VisualTreeHelpers 我相当使用它通常在 WPF 的可视化树中查找控件。它们可以这样使用:
You probably don't want to alter your Template in code-behind, because that would alter every control that uses that Template.
Instead, once your control has been Rendered, you can navigate it's visual tree to find the specific elements that need to be altered and change them. The
Loaded
event gets run after allRender
events get processed, so you should be able to adjust controls in a control's template during anyLoaded
event.I wrote a set of VisualTreeHelpers which I use quite often to find controls within WPF's visual tree. They can be used like this: