Creating a Base Window Class in WPF

Unlike Windows Forms, there is no Visual Inheritance in WPF. Luckily you don’t need visual inheritance as you can use User Controls to get a re-usable UI. There are times, however, when you want a base Window class so you can have common functionality in all your WPF windows. To accomplish this you can create a base class from which all your WPF windows can inherit. To use the base class you will need to make one simple change in both the XAML and in your code-behind class.

<Window> Element and Window Class

When you add a new Window to a WPF application it builds a .XAML file and a code-behind file. The XAML file has a <Window> element and the code-behind file has a partial class that inherits from “Window” or “System.Windows.Window” to be more specific. Notice the x:Class=”<Namespace>.<ClassName>” syntax in the XAML (See Figure 1). This x:Class name attribute must have the same name as the partial class in the code-behind. At compile time, the .XAML file is converted into a partial class that has the same name as the name of the class in the code-behind and inherits from the name of the top level element in the XAML; in this case “Window”.


Figure 1: The Window class and the inherited Window must match.

As long as these two items match the two elements in the partial class in the code-behind the compiler will be happy. If either of these two elements does not match, you will receive a compiler error.

Inherit from the Window Class

Now that you understand the basics of how the XAML and the code-behind are put together, you can now create a base Window class and modify the XAML and code-behind to use this new class.

If you wish to follow along with this article, create a new WPF application in Visual Studio. Add a new class to your project namedWindowBase. Modify this newly added class to inherit from the Window class. Add the following Imports/using statements at the top of the WindowBase class.

C#
using System.Windows;

Visual Basic
Imports System.Windows

The WindowBase class needs to inherit from the Window class by changing the code to look like the following:

C#
using System;
using System.Windows;

namespace WpfApplication1
{
  public class WindowBase : Window
  {
  }
}


Visual Basic
Imports System.Windows

Public Class WindowBase
  Inherits Window
End Class

Modify the code-behind of the Window1.xaml file to inherit from the WindowBase class you just created. Your Window1 code-behind should now look like the following:

C#
public partial class Window1 : WindowBase
{
  public Window1()
  {
    InitializeComponent();
  }
}

Visual Basic
Class Window1
  Inherits WindowBase

End Class

If you were to compile the WPF application right now, you will receive the error message “Base class 'System.Windows.Window' specified for class 'Window1' cannot be different from the base class 'WindowBase' of one of its other partial types.” The reason is because while you changed the code behind to inherit from the WindowBase class, you need to change the XAML markup to reflect this same change.

The change you need to make is you need to modify the <Window> element to be <WindowBase>. However, <WindowBase> is not a part of any of the imported xml namespaces that are a normal part of the XAML markup. Thus, you need to add a namespace reference to the assembly that contains the WindowBase class. If you created a default WPF application project, the namespace you will add to the XAML is the following:

xmlns:src="clr-namespace:WpfApplication1"

Once you have added this namespace with the prefix of “src” you can now change the <Window> element to <src:WindowBase>. Be sure you modify the closing </Window> element to </src:WindowBase>. The complete source code for the XAML is shown below.

C#
<src:WindowBase
  x:Class="WpfApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:src="clr-namespace:WpfApplication1"
  Title="Window1" Height="300" Width="300">
  <Grid></Grid>
</src:WindowBase>

Visual Basic
<src:WindowBase
  x:Class="Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:src="clr-namespace:WpfApplication1"
  Title="Window1" Height="300" Width="300">
  <Grid></Grid>
</src:WindowBase>

At this point you should be able to compile the application and everything should compile correctly.

Adding Functionality

Now that you have a base Window class you can add code to that class that can be used in all of your WPF Windows. Once piece of functionality you might need is to check if your Window is in design mode or runtime. Add the following property to your WindowBase class.

C#
public bool IsInDesignMode
{
  get
  {
    return System.ComponentModel.
            DesignerProperties.GetIsInDesignMode(this);
  }
}

Visual Basic
Public ReadOnly Property IsInDesignMode() As Boolean
  Get
    Return System.ComponentModel. _
            DesignerProperties.GetIsInDesignMode(Me)
  End Get
End Property

From within your Window that inherits from the WindowBase class you can test to see if you are in design mode or in runtime mode.

C#
if(IsInDesignMode)
  // Do Something

Visual Basic
If IsInDesignMode Then
  ' Do Something
End If

Another piece of code that might come in handy in your WPF windows is the ability to read a resource dictionary XAML file and load it into the Resources of the Window. Below is the code you would add to the WindowBase class to do this.

C#
using System.IO;
using System.Windows.Markup;

public void OpenResourceDictionary(string fileName)
{
  ResourceDictionary dic = null;

  if (File.Exists(fileName))
  {
    using (FileStream fs = new FileStream(fileName, FileMode.Open))
      dic = (ResourceDictionary)XamlReader.Load(fs);

    this.Resources.MergedDictionaries.Add(dic);
  }
  else
    throw new FileNotFoundException(
      "Can't open resource file: " + fileName +
      " in the method OpenResourceDictionary().");
}

Visual Basic
Imports System.IO
Imports System.Windows.Markup

Public Sub OpenResourceDictionary(ByVal fileName As String)
  Dim dic As ResourceDictionary = Nothing

  If File.Exists(fileName) Then
    Using fs As New FileStream(fileName, FileMode.Open)
      dic = DirectCast(XamlReader.Load(fs), ResourceDictionary)
    End Using

    Me.Resources.MergedDictionaries.Add(dic)
  Else
    Throw New FileNotFoundException( _
      "Can't open resource file: " & fileName & _
      " in the method OpenResourceDictionary().")
  End If
End Sub

When you wish to load a new resource dictionary file at runtime into your Window you may do so with some very simple code from within your Window.

C#
OpenResourceDictionary("D:\Samples\Green.xaml");

Visual Basic
OpenResourceDictionary("D:\Samples\Green.xaml")

Summary

So, that is all there is to creating your own base Window class from which all your Window objects can inherit. There is a lot of functionality that you will want to make available to your Window classes. Creating a base Window class is a great way to expose this functionality. It just takes a little bit of tweaking to your XAML and your code-behind to get all this great functionality.


NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Window Inheritance" from the drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
作者:Angelo Lee
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文地址:https://www.cnblogs.com/yefengmeander/p/2887676.html