完全覆盖 WPF 控件需要几个步骤。有些是必需的,有些是可选的,具体取决于您的需要。我将为您解释两个重要的:
创建新的默认样式
每个 WPF 控件都有一个默认样式,其中包含它的视觉表示和覆盖属性。现在,如果您从控件派生 WPF 仍然认为您想要使用此默认样式,则更改您在静态构造函数中更改 DefaultStyle 像这样
class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
}
现在,如果您使用 MyButton WPF 会尝试为 MyButton 查找样式,而不是为 Button 查找样式。OverridesDefaultStyle 是样式中的一个属性,在某些时候可能也很方便。通常这些默认样式应该放在与主题相关的 xaml 中。
覆盖类时的事件处理程序
在 a 中是正确的, ControlTemplate否则Style您不能使用使用 event like 的语法糖Click="OnClick"。关键是,视觉表示尽可能地与逻辑部分分离。还有其他方法可以克服这个问题,使用 OnApplyTemplate 方法。通过覆盖它,您可以询问模板“给我这个控件”,然后您只需在其中添加您的事件。
override OnApplyTemplate()
{
var innerChild = Template.FindName("PART_InnerChild", this) as MyInnerControl;
if(innerChild != null)
innerChild.SomeEvent += OnSomeEvent;
}
注意:按照约定,这些控件的名称通常以 PART_ 开头,这也可以在 WPF 基本控件中看到。这是告诉设计师“没有这个控件,逻辑部分可能会中断”的好方法。还有属性TemplatePart但它并不重要,WPF 不关心它。AFAIK Expression blend 对它进行了一些处理,我个人用它来告诉其他人什么样的内部控件对于使这个控件起作用是绝对必要的。
个人建议
从类派生通常是我们尝试自定义控件时所做的最后一步。因为要使其完全正常工作需要做很多工作,而且它可能会限制可重用性,所以我们尽量避免它,例如除了模板覆盖和样式之外,还有一个很好的替代方案;附加行为。
最后,一篇不错的 MSDN文章涵盖了整个主题。
希望有帮助