In continuing our WPF themed series, I invite you to go through this collection of seven best practices.
No matter if you are starting new or have an existing application, it wouldn’t hurt to be aware of your code’s performance and what can be done in this direction.
All these are insights that I discovered over time, by seeing how certain pieces of code that I wrote were performing. Some of them, I was able to improve from a performance standpoint. Others, from a code or even from a logical standpoint.
Here they are:
#1 IsVisible Boolean property
If you need to update the visibility on an UIElement, the standard recommendation that you will find (on StackOverflow for example) is to use the Boolean property in view model “IsVisible” and then a converter in which you will convert the bool IsVisible to Visibility.Visible or Visibilty.Collapsed.
Incorrect approach
Using a converter means extra code. To make a property visible or invisible, you must call a converter, which you must instantiate. It’s time and energy consuming.
Optimum approach
The optimum solution and a more logical one, would be to use exactly the data you need, as in to directly use the Visibility type for the IsVisible property in view model. No need to reinvent the wheel.
#2 Update only when need to
Sometimes, a user will begin to change a value in a field only to change it back again. In this case, there’s no need to send an update to the database, because nothing has changed. But I noticed that the most used approach is the following:
Incorrect approach:
This is not exactly the optimum approach, because the update is sent no matter if the property is changed.
Optimum approach
The better method would be, if the newly entered value is equal to the old one, that no update should be sent:
Optimum approach II
As a second good option, Microsoft offers a BindableBase class that handles all this code in one line.
So, you can use BindableBase from prism and raise event via SetProperty method. If BindableBase is not available for your current project, just implement in a base class SetProperty method.
#3 General Styles
By now it has become common sense to have all the styles in one place. If you have them scattered through all the files of your app, the moment you want to, for example, update all the buttons to be green instead of grey, you must make changes in 20, 50, 100 different places. If you have them in one file and from there, that style is called by every element that needs it, when you need a change, you can make the change in one place, and then it propagates everywhere that style is used.
It saves work, but also saves you from having duplicate code. Move general styles , colors or data in resource dictionaries and dictionaries added on the App.xaml and from there use StaticResource to reference from it. This is also useful if you have themes.
#4 Converters
For Converters, I don’t necessarily see a bad vs. optimum approach. You can either derive them from MarkupExtension – a class from Microsoft and use them directly where you need them; or you can create an instance in the control resource region and then reference it with Resource – you will get the same result, but the XAML code will be harder to read.
First approach
The converter is not derived from MarkupExtension. You get to do this instantiation of some extra code in XAML, and this “pollutes” the file with some useless code, like in the following example:
Second approach
If you use MarkupExtension, you can use it directly in XAML, without needing another 2-3 lines of code. In this way, any converter that’s done by this method will be used directly where you need it. It would translate as lighter, more readable, less cluttered code, like in the next example:
Neither method is a mistake, it’s up to the programmer’s preference. But this markup extension thing is not very popular on Stack Overflow.
Third approach
If you want to be even more efficient, you can add a converter with MarkupExtension to a resource dictionary – that way it will only be instanced once. Like the following:
#5 Binding delays
This is useful for text boxes. By default, for each letter entered, the app will send information to the database that another letter has been added to the word you type. However, if you set a binding delay of 1-2 seconds, depending on the requirements, only every 2 seconds an update would be sent to the database. And, in two seconds, the user has time to type six to seven characters. This means one update instead of up to 6 updates for every 2 seconds, when using binding delays.
This results in better performance, less energy consumed, etc.
#6 Triggers vs VisualStates
Again, this is not a bad vs good approach case. Most of the times, triggers are the easiest way to obtain a visual effect, but in some cases, this will result in bad performance (e.g. mouse over a list of items via trigger will result in a “ghost/delayed highlight, whereas the VisualStates mechanism will improve the highlight). So just consider that VisualStates are a better approach in this case.
Here are some examples for easy comparison:
Using Triggers
Triggers are much easier to use (3 lines of code). That would be easier to write:
Using VisualStates
VisualStates are more native to WPF than Triggers. They require more code, but they are faster and better performant. The advantage is that some of this code is standard:
For example, I had a situation where I had to use a ghost shadow, and I could clearly see the difference, the highlight lagging far behind the mouse, which you don’t want to happen.
It all comes down to testing sometimes: if the delay is not noticeable to the user, it may be OK to use triggers, that involve less code. But in cases where performance is important, it will be better to use visual states.
#7 TemplateBinding
My point of view is that – when you are working inside a template, the best approach is to use TemplateBinding. Otherwise, some UI bugs can be generated (UI inconsistency).
TemplateBinding allows you to bind a button to some properties inside the button.
Inside the button, the styling is composed of several elements: a border, inside the border a panel, inside the panel an icon, and inside the icon a textbox. If we set a red background on the button, inside, when we define the border and the panel, we must set the colors to each element.
Here are two examples to illustrate this:
Bad approach
Correct approach
#… The list is open
These are, of course, just few of the better alternatives that you can use when writing your code. If you’ve come across other examples of performance centered WPF code writing tips, or want to share a different point of view to the ones in the current list, please do so in the comments section below.