【问题标题】:OnApplyTemplate not called in Custom ControlOnApplyTemplate 未在自定义控件中调用
【发布时间】:2020-11-27 17:30:57
【问题描述】:

我有一个使用一些 PART 控件的自定义控件:

 [TemplatePart(Name = "PART_TitleTextBox", Type = typeof(TextBox))]
    [TemplatePart(Name = "PART_TitleIndexText", Type = typeof(Label))]
    [TemplatePart(Name = "PART_TimeCodeInText", Type = typeof(TextBlock))]
    [TemplatePart(Name = "PART_TimeCodeOutText", Type = typeof(TextBlock))]
    [TemplatePart(Name = "PART_ApprovedImage", Type = typeof(Image))]
    [TemplatePart(Name = "PART_CommentsImage", Type = typeof(Image))]
    [TemplatePart(Name = "PART_BookmarkedImage", Type = typeof(Image))]
    public class TitleBoxNew : Control
    {
        static TitleBoxNew()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(TitleBoxNew),
                new FrameworkPropertyMetadata(typeof(TitleBoxNew)));
        } 

        public TitleBoxNew() { }

        // ... rest of class
    }

此控件覆盖 OnApplyTemplate:

public override void OnApplyTemplate()
{
      base.OnApplyTemplate();

      InitializeEvents();
}

大多数时候效果很好。我已经在窗口的自定义选项卡控件中添加了控件,并且永远不会为该控件调用 OnApplyTemplate!为什么这不符合我的预期?

【问题讨论】:

  • 您是第一次加入,您使用的是 F 字。在发布之前尝试看看这个社区是否喜欢它。

标签: wpf


【解决方案1】:

对于可能偶然发现这篇文章的其他人,我遇到了同样的问题,我设法通过将以下内容添加到包含我的自定义控件的项目的 AssemblyInfo.cs 中来解决它:

[assembly: ThemeInfo(
    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
    //(used if a resource is not found in the page, 
    // or application resource dictionaries)
    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
    //(used if a resource is not found in the page, 
    // app, or any theme specific resource dictionaries)
)]

我的控件模板位于与控件相同的项目中的文件 Theme/Generic.xaml 中。

【讨论】:

  • 这拯救了我的一天。字面上地。非常感谢。
  • 这解决了我在将一些 WPF 自定义控件移动到最初未创建为“WPF 自定义控件库”的常规 C# 类库后的问题。顺便说一句:还将所需的 XML 元素添加到 .csproj 以将类库升级为“真正的”WPF 类库。
【解决方案2】:

另外两个答案是正确的……但不完整。根据this post(以及我刚刚解决此问题的经验),您需要检查四件事:(由于某种原因,如果我使用数字或破折号,这篇文章中的代码块将不会保持格式......所以字母是的)

A.控件模板和样式应位于项目根目录的Generic.xaml 文件夹中,该文件夹名为Themes

B.确保Generic.xaml中的命名空间正确

C.在控件的构造函数中设置样式键。还广泛建议您将以下内容放入静态构造函数中。

 static YourControl()
 {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(YourControl), new FrameworkPropertyMetadata(typeof(YourControl)));
 }

D.确保您的 assemblyinfo.cs 中有以下内容

 [assembly: ThemeInfo(ResourceDictionaryLocation.None, 
 //where theme specific resource dictionaries are located
 //(used if a resource is not found in the     
 // or application resource dictionaries)
 ResourceDictionaryLocation.SourceAssembly 
 //where the generic resource dictionary is located
 //(used if a resource is not found in the page,
 // app, or any theme specific resource dictionaries)
 )]

【讨论】:

  • Step A 足以解决我的问题,谢谢! (uwp)
  • 我的主题文件夹不在项目的根目录中。这解决了问题。
  • 对我来说也是 A。谢谢!
【解决方案3】:

我看不到你的构造函数,但别忘了设置 DefaultStyleKey:

DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleBoxNew), new FrameworkPropertyMetadata(typeof(TitleBoxNew)));

【讨论】:

  • 是的,我不得不提一下,我已经知道了: static TitleBoxNew() { DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleBoxNew), new FrameworkPropertyMetadata(typeof(TitleBoxNew))); } 公共 TitleBoxNew() { }
  • 请编辑您的原始帖子以包含您的构造函数; cmets 不是代码的正确位置。
【解决方案4】:

我将添加我自己的答案,因为上述两个答案都不完整,因为我一直在努力解决这个问题。

正如上面MoMo和Kai G所说:

A.控件模板和样式应位于 Generic.xaml 文件位于项目根目录的名为 Themes 的文件夹中。

B.确保您的命名空间在 Generic.xaml 中是正确的

C.在控件的构造函数中设置样式键。

D.确保主题属性在 assemblyinfo.cs 文件中

但您还需要确保将构建操作的 Generic.xaml 文件设置为 Page:Do Not copy。

如果您未能执行此操作或该值以某种方式设置为除此之外的其他值,则不会调用 OnApplyTemplate() 方法。

【讨论】:

  • D 部分特别重要,IMO。
【解决方案5】:

@MoMo 的答案是正确的,但另外:

E:预计 Themes/Generic.xaml 位于项目的根目录中。如果不是这种情况并且您的 Generic.xaml 不在根目录中,那么您必须在根目录中创建一个带有 Generic.xaml 的目录 Themes(Generic.xaml 只是 ResourceDictionary 类型)。在该 Generic.xaml 中,您需要引用 Generic.xaml 的位置。

例如:

<ResourceDictionary Source="/Foo.Bar;component/Controls/FooControl/Themes/Generic.xaml" />

【讨论】:

    【解决方案6】:

    除了上述所有内容之外,您应该检查一下,

    实际上调用了 OnApplayTemplete(),但是在所有属性更改调用之后,我不知道为什么,应该首先调用它

    因此,如果您使用 PART 名称来获取元素,则会出现错误,因为 wpf 在调用 OnApplayTemplete() 之前不会找到 因此,您必须在任何代码前添加 if (your part element != null) 条件取决于 PART 名称

    然后在 OnApplayTemplete() 方法中,它会再次自动调用你所有的逻辑方法,它会正常工作

        TextBox textBox;
        public override void OnApplyTemplate()
                {
                    base.OnApplyTemplate();
                    //onther way to get elements & PARTs
                    textBox= Template.FindName("PART_TitleTextBox", this) as TextBox;
    
                    MyMethod();
        
                }
        private void MyMethod()
        {
    if (textBox == null) return;
    //your logical code here
        }
    

    【讨论】:

      猜你喜欢
      • 2020-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 2018-10-09
      • 1970-01-01
      • 2021-08-08
      相关资源
      最近更新 更多