Previously I had the template of the UserControl directly set, not through a style, and everything worked nicely: the root of the content could be accessed using this.Template.LoadContent() or through this.Template.FindName("MyControlName", this), both calls being done in OnApplyTemplate, after the base.OnApplyTemplate() call. Now I need a style because I use two DataTriggers to display a type of Control or another in function of a Binding value.
By debugging with the XAML below, I see that after the base.OnApplyTemplate call this.Template.LoadContent() returns a Border with its Child set to an empty ContentPresenter. I wish to get the wpf:TimeSpanPicker element.
I have read this answer and it does not help me because of the result of debugging presented above. The same with this answer.
Before, my UserControl had this directly inside (in its XAML file):
<UserControl.Template>
<ControlTemplate>
<wpf:TimeSpanPicker
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="MyTimeSpanPicker"
Margin="0,0,7,0"/>
</ControlTemplate>
</UserControl.Template>
Now I have this:
<UserControl.Style>
<Style TargetType="UserControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Mode=OneWay, Converter={StaticResource ClockToType}}"
Value="TimerData">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<wpf:TimeSpanPicker
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="MyTimeSpanPicker"
Margin="0,0,7,0"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Mode=OneWay, Converter={StaticResource ClockToType}}"
Value="AlarmData">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="UserControl">
<Button>Not yet implemented</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
The code-behind includes:
internal wpf_timespanpicker.TimeSpanPicker GetMyTimeSpanPicker()
{
return (wpf_timespanpicker.TimeSpanPicker)Template.LoadContent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
GetMyTimeSpanPicker().TimeSpanValueChanged += MyTimeSpanPicker_TimeSpanValueChanged;
}
private void MyTimeSpanPicker_TimeSpanValueChanged(object sender, EventArgs e)
{
CurrentValue = GetMyTimeSpanPicker().TimeSpan;
}
The ClockToType value converter simply transforms one of my Clock classes' instances to their type name.
Update
Now it partially works because of the answer but I need to set the TimeSpan dependency property of the TimeSpanPicker when the CurrentValue dependency property of the UserControl is changed, and the CurrentValue dependency property can be changed when the time span picker is not yet Loaded. What is the best way to postpone this setting? Placing an ApplyTemplate call before the setting does not seem to work because the class variable in which I keep a reference to the TimeSpanPicker is null:
private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var o = d as ClockValueScreen;
o.ApplyTemplate();
o.MyTimeSpanPicker.TimeSpan = (TimeSpan)e.NewValue; // but here o.MyTimeSpanPicker is null
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate(); // execution reaches this point from the ApplyTemplate call above
}
private void MyTimeSpanPicker_Loaded(object sender, RoutedEventArgs e)
{
MyTimeSpanPicker = (wpf_timespanpicker.TimeSpanPicker)sender;
MyTimeSpanPicker.TimeSpanValueChanged += MyTimeSpanPicker_TimeSpanValueChanged;
}