如何从代码隐藏中访问UserControl中样式的Setter中ControlTemplate中定义的Control实例?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从代码隐藏中访问UserControl中样式的Setter中ControlTemplate中定义的Control实例?相关的知识,希望对你有一定的参考价值。
以前我直接设置了UserControl的模板,而不是通过样式,一切都很好用:可以使用this.Template.LoadContent()或通过this.Template.FindName(“MyControlName”,这个来访问内容的根目录。 ),在base.OnApplyTemplate()调用之后,两个调用都在OnApplyTemplate中完成。现在我需要一个样式,因为我使用两个DataTriggers来显示一个Control类型或另一个函数的Binding值。
通过下面的XAML调试,我看到在base.OnApplyTemplate调用this.Template.LoadContent()之后返回一个Border,其Child设置为一个空的ContentPresenter。我希望得到wpf:TimeSpanPicker元素。
我已经阅读了this答案,但由于上面提到的调试结果,它对我没有帮助。与this answer相同。
之前,我的UserControl直接在其内部(在其XAML文件中):
<UserControl.Template>
<ControlTemplate>
<wpf:TimeSpanPicker
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="MyTimeSpanPicker"
Margin="0,0,7,0"/>
</ControlTemplate>
</UserControl.Template>
现在我有这个:
<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>
代码隐藏包括:
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;
}
ClockToType值转换器只是将我的一个Clock类的实例转换为它们的类型名称。
Update
现在部分工作是因为答案,但我需要在更改UserControl的CurrentValue依赖项属性时设置TimeSpanPicker的TimeSpan依赖项属性,并且当时间跨度选择器尚未加载时可以更改CurrentValue依赖项属性。推迟此设置的最佳方法是什么?在设置之前放置ApplyTemplate调用似乎不起作用,因为我保留对TimeSpanPicker的引用的类变量为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;
}
您不能使用OnApplyTemplate()
,因为在解析绑定并且转换器返回值“TimerData”之前,没有可用的TimeSpanPicker
元素。
你可以做的是在XAML中连接事件处理程序:
<ControlTemplate TargetType="UserControl">
<wpf:TimeSpanPicker
Loaded="OnLoaded"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Name="MyTimeSpanPicker"
Margin="0,0,7,0"/>
</ControlTemplate>
...然后在你的代码隐藏中处理它;
private void OnLoaded(object sender, RoutedEventArgs e)
{
wpf_timespanpicker.TimeSpanPicker timeSpanPicker = ( wpf_timespanpicker.TimeSpanPicker)sender;
}
编辑:如果您想在TimeSpanPicker
属性更改时使用CurrentValue
执行某些操作,可以使用VisualTreeHelper
类在可视树中查找它:
private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var o = (ClockValueScreen)d;
var timeSpanPicker = FindVisualChild<wpf_timespanpicker.TimeSpanPicker>(o);
//...
}
private static T FindVisualChild<T>(Visual visual) where T : Visual
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
if (child != null)
{
T correctlyTyped = child as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
T descendent = FindVisualChild<T>(child);
if (descendent != null)
{
return descendent;
}
}
}
return null;
以上是关于如何从代码隐藏中访问UserControl中样式的Setter中ControlTemplate中定义的Control实例?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 UserControl 访问 WPF 页面中的公共变量?