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).
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:
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"