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