Creating Custom WPF Controls from Code

In the article, titled How to easily customize WPF controls – and 5 reasons why you should not do it in a large project, we realized that it is easy to customize WPF controls from XAML code. In this article, we are going to start to build our own WPF control library. The code snippets referred in this article are in the https://github.com/atzimler/WpfWednesday.git git repository.

The starting point for our expedition is the folder Z00_OnlyOneProject of the repository. This folder contains a project called WpfApplication, which is a WPF application. The application is one main window with a button on it. This button when you hover the mouse over it, instead of becoming highlighted in the normal Windows way, it is highlighted in purple. The starting application achieves this through a style in the MainWindow.xaml file called PurpleHoverButton.

Further down the road, we realize that we are implementing this style repeatedly in different applications, so we decide to create a library from it. We move all the styles and the button definition itself into PurpleButton.xaml and separate it into PurpleButtonLib. After separating the code, we clean it up a bit and the result can be seen in the Z01_MoveButton folder. So far, everything is going fine and when we start the application, the button reacts as expected.

As the development progresses, a business requirement comes in. All buttons must be colored with having background color set to aqua and border color set to dark cyan. Not a problem, after all we kept the code clean, so we are going to create a customized control that derives from PurpleButton called AquaPurpleButton and we set all the coloring there.

Let’s implement it. Add the following to the WpfApplication project:

Well, this is nice and clear what we want to do, but unfortunately it will not compile, so you will have to remove it. The project status after this modification is in Z02_Deriving directory. Unfortunately, if you defined a control in XAML then you cannot use it to base another control that is being defined in XAML. You will get a nice compiler message about this.

Let’s try it in a different way. If we cannot define it in XAML, we can define it in code, right? After all, we are used to this, this the way the old way anyway. Let’s add this code block to the PurpleButtonLib:

Works like a charm. We check our code into the version control system, and submit the work item ticket for code review. Just in time, because it is the end of the working day. (Z03_Deriving)

Next day, an email awaits our arrival. Unfortunately, the architect on the project was not leaving early, so had the time to review our code. AquaPurpleButton is not a generic code related to the functionality of the PurpleButtonLib, but a code related to the functionality of WpfApplication only, so we are asked to move the class to its correct location, otherwise the solution is perfect. Not a problem.

We quickly move the button, adjust the namespace in AquaPurpleButton.cs and MainWindow.xaml, after all we like the fact that most of our code reviews are passing, and recompile. Compiles perfectly, let’s check it in. (Z04_Deriving)

Later, the build integration system starts to report that the application is crashing on load. It throws a cryptic exception with the message:

The component ‘WpfApplication.AquaPurpleButton’ does not have a resource identified by the URI ‘/PurpleButtonLib;component/purplebutton.xaml’.

After seeing this, it is not a surprise that almost at the same time we received the build message, we received a message from the architect too:

You fix the build problem.

So, what should we do? A bit of googling will not result in any solution, because it seems that everybody is frustrated with the same error. If we are good enough we can even come up with this link: https://connect.microsoft.com/VisualStudio/feedback/details/508801/wpf-deriving-a-class-from-a-xaml-defined-class-in-another-module-fails. This link is hard to find, I thought that I accidentally closed the tab with it, and tried to find it again and was not able to. Luckily, I could find the tab itself in the browser. The discussion provided by the link is describing that this is a known problem of the WPF system and will not be fixed in the next release. That next release was by the way in 2012. It is 2017 and the problem is still there.

There is one more component of the problem that can be changed. We could transform the base class to code, so that it will not use XAML for its definition. As a next step, let’s try that. We drop the PurpleButton.xaml control and create a PurpleButton.cs instead with the following content in the PurpleButtonLib project:

 

Now our hovering works again. However, the customization from the AquaPurpleButton disappeared. If you pay attention while using the control, you will also notice that it is not exactly reacting as the non-changed version. The reason behind this is that creating a style from code is not a game where you just override something. It is either you do it totally, or you don’t do it. The above example only contains the hovering and default look related codes. (Z05_Deriving)

As we have seen in this article, control development in a way where you can easily extend it is a meticulous work. The biggest challenge, because you cannot access the original template except by creating a style for it in the XAML code as we have seen in the previous article, is to create the code counterpart of that XAML style. Luckily this is only needed when you want to change a very fundamental behavior of a standard control. Changing the hover color of a button is such a behavior.

Next time we will fix the problem with the changes in the base class so that AquaPurpleButton will work again properly. After fixing the button, in the series of articles we will explore different areas of custom WPF control creation.

You can connect with me on LinkedIn, Twitter or you can register on the blog. Share if you found this article useful or know somebody who would benefit from reading it.

By subscribing to the email list, you will be notified about new posts.
Loading

 

 

No comments yet.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Powered by WordPress. Designed by WooThemes