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 named WindowBase. 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".

19 Comments

  • The simplest option is to remove the inheritance from the code-behind. The automatically generated part of the partial class already declares the inheritance, so there's no need to repeat it:

    public partial class Window1
    {
    public Window1()
    {
    InitializeComponent();
    }
    }

  • RichardD,

    Great suggestion! I forgot about that!

    Thanks,
    Paul

  • Hello,

    This was a great, simple write-up on the procedure for doing this otherwise not-so-clear task and it's very much appreciated.

    I'm doing a few experiments (because I'm just damn curious if it'll work) such as trying to whip up an AppBar for WPF base class.

    A key (which is now obvious but wasn't) to know for WPF in this situation is the xaml.cs/vb is a backing for the xaml file itself and not in any way the traditional class backing I'm used to for WinForms development. It was your article that made that fact 'click' in my brain finally and I thank you for that :)

    Regards,
    Michael

  • Hi Michael,

    Glad this helped you understand! I love it when something I put down helps someone.

    Good luck with your AppBar!
    Paul

  • I'm new to coding and was using WinForms until at a sac.net meeting in Sacramento a few months ago you convinced me with a smile to switch to WPF (and building class libraries). I switched the next day. Recently I tried to inherit from a Window and hit my first big WPF hurdle. I entered "inherit window wpf" into the MSDN Library search box and the topmost entry was your solution! I'm now in awe and declare you a true folk hero .net guru!

  • I thought this was a good tutorial, however, I am a VB.net programmer: not by choice, it's a VB shop. Your initial image at the start shows the windows created by a C# application and not a VB application. I have been a big fan of yours since the keystone video series and thought I needed to point out that discrepancy, since it takes credibility away from a VB viewer, when your pictorial doesn't match what we generate to follow through the process. The remainder of it was ver useful and keepem coming. Thanks

  • mikec,

    Sorry, but most people use C# these days and I did not want to have two pictures. I did have VB in the text however, so the VB person was not left out. Most of my samples I do in both languages. However, the majority of people want C# these days unfortunately. I love VB, but I have to also go with what the market wants!

    :)

  • Im new to this. I tried your inheritance solution here and got this error message on the WPF form: "The document contains errors that must be fixed before the designer can be loaded".

    I then downloaded your VB and C# examples and both give the same errors when I tried to open the main form.

    I am using Visual Studio 2010.

    Steve

  • Hi Steve,

    Sorry you are having problems. What edition of VS.NET 2010 are you using? If it is one of the "free" editions or a "Starter" or "Education" type-editions, then this might not work.

    I have had a lot of people use this and never had any problems.

    Paul

  • Thanks a lot! I used it and it works really good! ^^
    You only forgot to say that de BaseWindow needs to be a .cs file, with no XAML.

    Thanks my friend :)

  • Hello,
    that doesn't work.
    I get an Error.

    Can anybody send me the example source?

  • Kate,

    This does work. You can download the sample code at my website. The instructions are at the end of this article.

    Paul

  • ok it works.thanks for you fast reply.
    But i have a question:
    i want that the windowBase instantiate elemtents not only resourcedictonary. is that possible?

  • I would like that:
    the windowbase load a xaml file that contains a menu for all my windows, which inherits from windowbase.
    is that possible????

  • Hi Paul,

    I added this to the WindowBase class:

    // Press ESC to close any window
    private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
    { if (e.Key == Key.Escape) Close(); }

    But it doesn't seem to fire. What am I doing wrong?

    Les

  • Hi Les,

    Sorry it took so long to get back to you! Been very busy!

    You need to override the OnPreviewKeyDown event:

    protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
    {
    if (e.Key == Key.Escape) Close();

    base.OnPreviewKeyDown(e);
    }

  • Great man! I was looking for these tips on entire internet LOL, work's perfectly. Thank you.

  • Clint,

    No, this still works. I use this technique all the time. I am using Visual Studio 2010.

    The one thing I notice is that your x:Class="myEmailer...", but your base class is in another namespace. Is your ClientWindow in another DLL? If so, then you need the Assembly reference in your xmlns:src="...".

    Paul

  • Very useful post, thank you a lot!

Comments have been disabled for this content.