如何为泛型控件应用全局ControlTemplate?
泛型ControlTemplate无法触发OnApplyTemplate的解决方案
问题描述
定义了泛型控件:
public class BarChart<T> : ContentView { protected override void OnApplyTemplate() { base.OnApplyTemplate(); } }
并关联了模板和样式:
<ControlTemplate x:Key="BarChartControlTemplate"> [...] </ControlTemplate> <Style TargetType="{x:Type controls:BarChart`1}"> <Setter Property="ControlTemplate" Value="{StaticResource BarChartControlTemplate}" /> </Style>
但OnApplyTemplate()始终未被调用,特化控件(如public class IntBarChart : ContentView)可正常工作,但不符合泛型需求。尝试让泛型控件继承非泛基类:
public class BarChart : ContentView { protected override void OnApplyTemplate() { base.OnApplyTemplate(); } } public class BarChart<T> : BarChart { protected override void OnApplyTemplate() { base.OnApplyTemplate(); } }
问题依旧存在,询问是否有可行的全局模板方案。
可行解决方案
方案1:在泛型控件代码中手动加载并应用模板
由于XAML对泛型类型的全局样式支持存在限制,可在泛型控件的构造函数或初始化逻辑中,从资源字典手动获取模板并赋值:
public class BarChart<T> : BarChart { public BarChart() { if (Application.Current.Resources.TryGetValue("BarChartControlTemplate", out var template)) { ControlTemplate = template as ControlTemplate; } } protected override void OnApplyTemplate() { base.OnApplyTemplate(); // 此处可处理模板内元素的逻辑 } }
这种方式绕过XAML对泛型类型的识别限制,直接在代码层绑定模板,确保OnApplyTemplate被触发。
方案2:使用附加属性统一应用模板
创建一个附加属性,为任意BarChart泛型实例设置模板,可在XAML中直接对泛型控件实例应用:
public static class BarChartTemplateHelper { public static readonly DependencyProperty ApplyTemplateProperty = DependencyProperty.RegisterAttached( "ApplyTemplate", typeof(bool), typeof(BarChartTemplateHelper), new PropertyMetadata(false, OnApplyTemplateChanged)); public static bool GetApplyTemplate(DependencyObject obj) { return (bool)obj.GetValue(ApplyTemplateProperty); } public static void SetApplyTemplate(DependencyObject obj, bool value) { obj.SetValue(ApplyTemplateProperty, value); } private static void OnApplyTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue && d is BarChart chart) { if (Application.Current.Resources.TryGetValue("BarChartControlTemplate", out var template)) { chart.ControlTemplate = template as ControlTemplate; } } } }
在XAML中使用方式:
<controls:BarChart<int> local:BarChartTemplateHelper.ApplyTemplate="True" />
这种方式既保留泛型灵活性,又能通过附加属性统一管理模板应用。
方案3:确保非泛基类的样式被正确继承
如果采用非泛基类的结构,需确保基类样式被正确应用,且泛型子类未覆盖ControlTemplate属性。先为基类定义样式:
<Style TargetType="{x:Type controls:BarChart}"> <Setter Property="ControlTemplate" Value="{StaticResource BarChartControlTemplate}" /> </Style>
泛型控件无需额外样式,因继承自BarChart会自动应用基类样式。若仍不生效,可在泛型控件构造函数中强制继承基类样式:
public class BarChart<T> : BarChart { public BarChart() { Style = FindResource(typeof(BarChart)) as Style; } }
内容的提问来源于stack exchange,提问作者Jeremy A.
相关产品推荐
相关产品推荐

