Jonathan Birkholz

Toggling Read Only With WPF

Ayende tweeted a brief code snippet of some WPF he threw together (well I assume he threw it together).

You can see the code snippet here : http://pastie.org/568259

He asked : Someone PLEASE tell me there is a better way than this (WPF)

I tweeted a brief snippet response to improve that tiny bit. The snippet can be found here : http://codesnippets.joyent.com/posts/show/2221

But I couldn’t just leave it at that. I wanted to show a different approach to solving the same problem. * A later tweet explained his problem was more a datacontext issue, which the snippet I provided should fix. This post does take a different look at how to approach handling read only controls.

How can we make a control ‘read only’ through binding?

The solution can be found here on my Git Hub Repository : http://github.com/RookieOne/WpfTogglingReadOnly

Ignoring all the other machinations, the money xaml is in the TextBoxStyle found in the Styles\TextBoxStyles.xaml resource dictionary.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Style x:Key="TextBoxStyle" TargetType="TextBox">
<Style.Triggers>
<Trigger Property="AttachedBehaviors:ReadOnlyBehavior.IsReadOnly" Value="True">
<!-- Readonly Template -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>

As you can see I use the IsReadOnly property on the base view model as a data trigger and then completely swap out the control template for the text box. This allows for complete customization of the read only look. It also pushes this functionality out into a style to be reused through the entire application.

Other things to note with the project (for those unfamiliar with the following practices):

1. Data Templates as Views

1
<DataTemplate DataType="{x:Type PersonView:PersonViewModel}">

So whenever WPF tries to resolve the PersonViewModel in a container, it will use this DataTemplate since I did not provide a key but only a DataType.

So in Window1 I can do…

1
2
3
<ContentControl>
<PersonView:PersonViewModel />
</ContentControl>

Again this is a very simple scenario so I am ignoring any presentation patterns on how the ViewModel is placed or ‘shown’. Also ignoring how dependencies can be resolved, etc.

And even though this is a content control, this works for items controls as well. So consider a stack of ‘views’. You could be accomplish this simply by placing a collection of ViewModels in an ItemsControl.

But really… that’s for another post.

2. Expression for INotifyPropertyChanged

I am also using a LambdaExpression to implement INotifyPropertyChanged. Essentially achieving safe notification and eliminating those nasty magic strings.

1
2
3
4
5
6
7
8
9
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged(this, m => m.FirstName);
}
}

Anyway.. that was a quick project I threw together. I hope it was helpful.

C#, WPF