C# 我可以使用CustomControl';s模板&x27;以类似UserControl的样式命名控件?
我们以前使用的C# 我可以使用CustomControl';s模板&x27;以类似UserControl的样式命名控件?,c#,wpf,custom-controls,C#,Wpf,Custom Controls,我们以前使用的UserControls,现在已转换为CustomControls。 UserControls通常具有命名的内部控件,可以从代码后面访问这些控件。 现在,我们在访问CustomControls的ControlTemplate的命名内部控件时遇到问题。 演示示例: CustomControl的控制模板: <Style TargetType="{x:Type controls:CustomControl1}"> <Setter Property="Templa
UserControls
,现在已转换为CustomControls
。UserControls
通常具有命名的内部控件,可以从代码后面访问这些控件。现在,我们在访问CustomControls的ControlTemplate的命名内部控件时遇到问题。
演示示例: CustomControl的控制模板:
<Style TargetType="{x:Type controls:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:CustomControl1}">
<Grid x:Name="PART_GridRoot" >
<!-- ... -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
private Grid _gridRoot;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_gridRoot = (Grid)this.Template.FindName("PART_GridRoot", this);;
}
public void Foo()
{
_gridRoot.Foo(); // Null reference exception if calling in too early state
}
问题是默认的ControlTemplate
分配得太晚(进入CustomControl1.Template
)。它不会应用于ctor
,也不会在调用ApplyTemplate
或手动测量时应用。有没有办法使默认的
ControlTemplate
更早地分配?我是否应该能够以类似UserControl的样式使用CustomControls模板的命名控件?
应用模板后,将调用应用模板。在此之前,无法获得命名的内部控件,因为它们尚未创建
这意味着像\u gridRoot
这样的字段只能在调用了应用程序模板之后才能访问。在前后都可以访问的地方,如果有,可以检查null
我可以加快模板的分配(实际上是默认的样式)
这样:
public class MyControl : Control
{
public MyControl()
{
ApplyDefaultStyle();
}
protected void ApplyDefaultStyle()
{
this.Style = WpfHelpers.GetDefaultStyle(this.GetType(), "OwnResourceDictionaryFullPath here");
this.ApplyTemplate();
}
}
public static class WpfHelpers
{
/// <summary>
/// Extracts the control's default Style from the resource dictionary pointed by the <see cref="resourceFullPath"/>.
/// So the Style without x:Key, with TargetType <see cref="controlType"/>
/// </summary>
public static Style GetDefaultStyle(Type controlType, string resourceFullPath)
{
Uri resourceLocater = null;
string assemblyName = null;
try
{
assemblyName = controlType.Assembly.GetName().Name;
resourceLocater = new Uri($"/{assemblyName};component/{resourceFullPath}", UriKind.Relative);
var resourceDictionary = (ResourceDictionary)Application.LoadComponent(resourceLocater);
var style = resourceDictionary[controlType] as Style;
return style;
}
catch(Exception e)
{
//Log.Warn
return null;
}
}
}
公共类MyControl:Control
{
公共MyControl()
{
ApplyDefaultStyle();
}
受保护的无效ApplyDefaultStyle()
{
this.Style=WpfHelpers.GetDefaultStyle(this.GetType(),“OwnResourceDictionaryFullPath here”);
this.ApplyTemplate();
}
}
公共静态类WpfHelpers
{
///
///从控件指向的资源字典中提取控件的默认样式。
///因此,不带x:Key的样式,带有TargetType
///
公共静态样式GetDefaultStyle(类型controlType,字符串resourceFullPath)
{
Uri resourceLocater=null;
字符串assemblyName=null;
尝试
{
assemblyName=controlType.Assembly.GetName().Name;
resourceLocater=新Uri($“/{assemblyName};component/{resourceFullPath}”,UriKind.Relative);
var resourceDictionary=(resourceDictionary)Application.LoadComponent(resourceLocater);
var style=resourceDictionary[controlType]作为样式;
回归风格;
}
捕获(例外e)
{
//日志。警告
返回null;
}
}
}
因此,我手动指定默认的样式
我知道我已经失去了自动主题化的可能性,但我可以接受
我只希望这个解决方案没有缺点,比如性能问题。对我来说,这与UserControl
的InitializeComponent()
调用非常相似
不过,是否有办法督促模板分配?手动应用它可能是一种好的做法吗?对不起,不是。OnApplyTemplate
是应用模板后的第一件事;这是你做任何事情的最早机会。对不起,不行。我希望能等一个恶作剧的回答,或者什么的。很难相信我是唯一一个对CustomControls有这种问题/误解的人。。。无论如何,谢谢你的回答,我给了+1可能,如果我们不重写DefaultStyleKeyProperty,我们可以在ctor中手动设置一个模板-这样行吗?这是一个好的练习吗?它会有类似于UserControl中InitializeComponent的效果吗?