了解WPF派生的WIndow类

我确信这很简单,但对于使用C#的WPF来说我是新手。 我知道从类中inheritance并且已经完成了很多次,例如在C#WinForms项目中……

public class MyClass : DerivedFromClass {} 

但是,在WPF中难倒,这就是问题所在。 我想构建我自己的一组控件,用作新学习项目的基线…预设我自己的样式,颜色,背景和其他function。 没问题。 首先使用WPF窗口启动并创建“MyWindow”。

现在,我想把这个基线“MyWindow”和子类THAT用于另一个类MySubClassedWindow。 因此,我创建了一个新的Window类,默认情况下,VS2010构建了表单的设计器和代码部分。 我在MySubClassedWindow上查看代码并查找

 partial class MySubclassedWindow : Window {} 

在使用WinForms的C#中,我只想改为(并且我已经包含了包含“MyWindow”声明的类库引用。

 partial class MySubclassedWindow : MyWindow {} 

当我这样做时,我得到一个编译错误

 Partial declarations of 'MyNameSpace.MySubclassedWindow' must not specify different base classes 

您的基类应该只是一个类文件(而不是Window )。

所以创建WindowBase.cs

 public class WindowBase : Window { // ... } 

在MainWindow中(例如)将xaml.cs文件更改为从WindowBaseinheritance

 public partial class MainWindow : WindowBase { public MainWindow() { InitializeComponent(); } // ... } 

在MainWindow.xaml中,包含WindowBase的命名空间,并将Window更改为base:WindowBase,如下所示

    

拥有一个基类Window类会带来一个严重的缺点,即绑定到基类中的属性要困难得多(目前接受的答案并不能解决这个问题) 。 如果你不能引用基本属性,那么inheritance的重点是什么? 我已经想出了如何在经过一段长时间之后设置它,并希望分享其他人将免于这种痛苦的希望。

您可能需要使用值转换器之类的东西,这些东西只能通过静态绑定来引用,在我看来,它在WindowBase类中是有意义的。 我已经包含了一个例子,因为我发现很难在设计和运行模式下一致地使用这些转换器。

您不能通过XAML设置此inheritanceWindow的x:Name属性,但如果使用以下方法,则可能不需要这样做。 我已经包含了一个如何设置名称的示例,因为inheritance自Window将不允许您在设计时在子类中设置名称。 我不建议在设计时依赖窗口名称,但设置d:DataContext应该为您处理任何绑定需求。

请注意,在设计模式而非运行模式下,WindowBase(或d:DataContext中指定的类)的副本将在设计模式下实例化并用作绑定上下文。 因此,在非常具体的情况下,您可能会看到数据差异,但在绝大多数用例中,这种方法应该足够了。

WindowBase.cs

““

 public class WindowBase : Window { //User-Defined UI Configuration class containing System.Drawing.Color //and Brush properties (platform-agnostic styling in your Project.Core.dll assembly) public UIStyle UIStyle => Core.UIStyle.Current; //IValueConverter that converts System.Drawing.Color properties //into WPF-equivalent Colors and Brushes //You can skip this if you do not need or did not implement your own ValueConverter public static IValueConverter UniversalValueConverter { get; } = new UniversalValueConverter(); public WindowBase() { //Add window name to scope so that runtime properties can be referenced from XAML //(Name setting must be done here and not in xaml because this is a base class) //You probably won't need to, but working example is here in case you do. var ns = new NameScope(); NameScope.SetNameScope(this, ns); ns["window"] = this; //Call Initialize Component via Reflection, so you do not need //to call InitializeComponent() every time in your base class this.GetType() .GetMethod("InitializeComponent", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) .Invoke(this, null); //Set runtime DataContext - Designer mode will not run this code this.DataContext = this; } //Stub method here so that the above code can find it via reflection void InitializeComponent() { } } 

SubClassWindow.xaml

     

后面的SubClassWindow代码(甚至不是构造函数)都不需要任何东西。