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的效果吗?