Self Registration Pattern for Singleton View Models in WPF

Where to store the Singleton View Model in WPF application, there are 2 common options:

Store in Resource Dictionary.

UI Designers prefers to store the WPF View Model into the Resource Dictionary because the objects in Resource Dictionary can be easily referenced in XAML.
But Developers must hate that way very much!
To fetch the object in Resource Dictionary from code behind must call the “FindResource” method of DependencyObject. And codes with tons of calls to “FindResource” method are ugly and very low efficient. The situation is worse since the accessibility to object in resource dictionary is also constrained by the Resource Scope, which means it is almost impossible to fetch the object from business logic.

Store in the Static Class.

I preferred to store the View Model in static class which is available globally. Developer can fetch the object by calling the static method, and designer also can fetch the object by using {x:Static} psudo-tag.
But it is still inconvenient somehow for designer, and it is somehow hard to provide design-time mockup data in this way.

For the previous 2 solutions, the pros and cons are obvious. But is it possible to combine these 2 approaches together to gains all the advantages but all the disadvantages.
The answer is Self-Registration Pattern.

The basic idea for Self-Registration Pattern is simple. It is obvious that we prefers to store the view models in Resource Dictionary, but we also want to access that object from Code Behind by calling static method.

So I designed the ViewModel class as following:

Self-Register View-Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ViewModel
{
#region Self Registration
public static ViewModel Default { get; private set; }
public ViewModel()
{
Default = this;
}
#endregion
}
View-Model Declaration
1
<vm:ViewModel x:Key="ViewModel"/>

You can see, the ViewModel has a globally visible static property named Default, and the class set the Default property to itself in its constructor.
Which means once the View Model is initialized in Resource Dictionary, it also set the instance reference to Default,
So designer can reference the view model easily with StaticResource Tag

Reference View-Model from XAML
1
<Control Property="{StaticResource ViewModel}"/>

And Developer also can access the view model by calling Static Property

Reference View-Model from C#
1
ViewModel.Default

Binding Visual Element Visibility to Mouse Over Event in WPF 4.0

I’m working on an user interface demo application in WPF.
I have a group of expander on the ui, and I want the expander show some descriptive text besides its caption while the mouse over it.
I used a TextBlock element to display the descriptive text, which is a child element in the control’s visual tree.

At first, I tried to use Style and Trigger to achieve this effect, but failed. Since Style Trigger apply its modification to the exactly same element that fires the trigger, which means if I would like to modify the property TextBlock, I can only fire the trigger by moving mouse over the TextBlock it self but the control that contains the TextBlock.

I tried some other ways, but all failed. Finally, I found I can achieve the effect by Data Binding!
Since TextBlock’s Visibility Property is a Dependency Property, and the TextBlock is contained by the Expander Control!
So we can Bind TextBlock’s Visibility Property to Expander Control’s IsMouseOver Property!
To achieve this, we need Relative Binding Source to locate TextBlock’s ancestor element, Expander Control.
Then we need BooleanToVisibilityConverter to convert the bool type value to Visibility value.

Here is the Xaml Code:

Data Template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<HierarchicalDataTemplate DataType="{x:Type m:CategoryItem}"
ItemsSource="{Binding Properties}">
<Border>
<Expander ToolTip="{Binding Tooltip}" IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}"/>
<TextBlock Name="HeaderDescription"
Margin="10,0,0,0"
Text="{Binding Description}"
Foreground="Green"
Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Expander}}, Path=IsMouseOver, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</Expander.Header>
<ListBox
DataContext="{Binding Properties}"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"/>
</Expander>
</Border>
</HierarchicalDataTemplate>

The problem introduced by making structure as a property

I met a strange problem while I was evaluating the Xaml Services that introduced in .net 4.
I created 2 types for Xaml Serialization Test:

Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Foo
{
public Foo() { }
public Foo(int a)
{
Random RND = new Random();
Value = RND.Next();
MyProperty = RND.Next();
Complex.Init(); // Complex is value type, which is automatically instantiated by default constructor.
}
[Ambient]
public int Value { get; private set; }
[Ambient]
public int MyProperty { get; private set; }
[Ambient]
public Nested Complex;
}
public struct Nested
{
public void Init()
{
this.Temp = Guid.NewGuid();
}
[Ambient]
public Guid Temp { get; set; }
}

So I can create a test instance of Foo by calling Foo(int a), e.g:

Instantiate Foo
1
Foo foo = new Foo(1);

But since Xaml doesn’t support serialize fields, I cannot apply AmbientAttribute to field, so the compilation fails. So I changed the field Complex of Class Foo to a property:

Change Field to Property
1
2
3
[Ambient]
// public Nested Complex;
public Nested Complex { get; set;}

Then the code compiles correct. But when I executed the code, I found the Temp property of Complex is empty guid. But I found I do called the Init method in the constructor of Foo. What’s the problem?

I believe that the problem must be special behavior related to ValueType. So I omitted to call Init(), I try to assign the Complex in Foo’s Constructor as following code

Replace the initializer with assignment
1
2
//Complex.Init();
this.Complex.Temp = Guid.NewGuid();

Compiles fails! Visual Studio tells me “Cannot modify the return value of ‘structTest.Foo.Complex’ because it is not a variable”

Still now, everything is explainable:

  1. It is because this.Complex is pointed to the variable itself that Code Complex.Init() works when Complex is field.
  2. It is because this.Complex is a return value, a copy of the original variable, instead of the original variable that the Code Complex.Init() doesn’t work when Complex is a property. this.Complex.Init() do changed the value of the Temp, but it modified the new copy instead of the original one.

So we need to be careful while change a value type field into a property, which may modify the program behavior a lot, and really difficult to debug while the code is complicated.