Clean your code

 

  Hi

 

While working on a complex UI application written in WPF I noticed that because I was using DataTemplates, Control templates and Styles both the Xaml and the Code Behind got very messy.

That is because once you start implementing those Code Behind EventHandlers you basically “mix” code from the template and code from the Window, plus you cannot access the elements in the template from the code behind.

You can move all the Templates and Styles to a ResourceDictionary but then you will not have the code behind available, so Templates that are more complex and interactive can’t go there.

 

Let’s look at the following example:

   1: <Grid>
   2:     <ItemsControl ItemsSource="{Binding}">
   3:         <ItemsControl.ItemTemplate>
   4:             <DataTemplate>
   5:                 <Border BorderBrush="Black" BorderThickness="2" CornerRadius="3" Margin="5">
   6:                     <StackPanel Orientation="Horizontal">
   7:                         <TextBlock Text="{Binding Name}" Margin="3"></TextBlock>
   8:                         <TextBlock Text="{Binding PhoneNumber}" Margin="3" 
   9:                                    x:Name="Number"  Visibility="Hidden"></TextBlock>
  10:                         <Button Content="Show Number" Margin="3" x:Name="ShowNumber" 
  11:                                Click="ShowNumber_Click"></Button>
  12:                     </StackPanel>
  13:                 </Border>
  14:             </DataTemplate>
  15:         </ItemsControl.ItemTemplate>
  16:     </ItemsControl>
  17: </Grid>

This application shows Records with the phone number hidden. Once you click on the “Show Number” Button in the template we change the Visibility of the Number TextBlock to Visible. Done this way you would have to bind the Visibility to a variable in the DataContext and then change it in the code behind of ShowNumber_Click, something like that:

   1: private void ShowNumber_Click(object sender, RoutedEventArgs e)
   2: {
   3:     ((sender as FrameworkElement).DataContext as Item).Vis = Visibility.Visible;
   4: }

Don’t forget to bind the TextBlock Visibility to the Vis property.

This is simple application but once the window gets “crowded” with templates, styles and the code behind starts to fill with event handlers and variables you get a big mess.

 

What can you do? Use UserControls.

 

All you have to do is copy the Template Code into a user control:

   1: <UserControl x:Class="TemplateUserControl.ItemControl"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   4:     <Border BorderBrush="Black" BorderThickness="2" CornerRadius="3" 
   5:             Margin="5" Height="30">
   6:         <StackPanel Orientation="Horizontal">
   7:             <TextBlock Text="{Binding Name}" Margin="3"></TextBlock>
   8:             <TextBlock Text="{Binding PhoneNumber}" Margin="3" 
   9:                        x:Name="Number"  Visibility="{Binding Vis}">
  10:             </TextBlock>
  11:             <Button Content="Show Number" Margin="3" x:Name="ShowNumber" 
  12:                     Click="ShowNumber_Click">
  13:             </Button>
  14:         </StackPanel>
  15:     </Border>
  16: </UserControl>

And specify this control as the DataTemplate:

   1: <Grid>
   2:     <ItemsControl ItemsSource="{Binding}">
   3:         <ItemsControl.ItemTemplate>
   4:             <DataTemplate>
   5:                 <my:ItemControl></my:ItemControl>
   6:             </DataTemplate>
   7:         </ItemsControl.ItemTemplate>
   8:     </ItemsControl>
   9: </Grid>

We have just separated the Item Code Behind and the Window Code Behind Which I think helps to keep things arranged but, we also got another thing, because they are encapsulated in a UserControl we can access the Controls in the template! We can make the ShowNumber_Click event handler look like this:

   1: private void ShowNumber_Click(object sender, RoutedEventArgs e)
   2: {
   3:     Number.Visibility = Visibility.Visible;
   4: }

Which I personally prefer. I don’t like sticking UI related setting inside the data.

So, by encapsulating the template in a UserControl we have achieved 3 things:

  1. Both Xaml and Code Behind are cleaner, and you know that if you are looking at Window1.xaml.cs all the code there relates to the Window and only him which leads to better maintainability, the same thing goes for the UserControl al the Code Behind there relates to the UserControl (our former DataTemplate).
  2. We have much more flexibility for actions inside the Template because it is a UserControl now.
  3. No mixing the UI settings and the Data.

Do you have a better way? Let me know what you think

 

Amit.

Tags :

10 Responses to “Tidy Up Your Xaml And Code Behind, Use UserControls Inside Templates”


  1. Jeremy

    Said on March 3, 2009 :

    Hi,

    I’m a big fan of MVVM which means I’m a big fan of empty code-behind too ! For this particular problem, I think I’d use a different approach (a 100% XAML solution as I love them :p)

    Here is my sample:

    Basically, I use a ToogleButton (the base control for CheckBox and RadioButton) which can hold a state (checked or not). I use this property to databinding the visibility of the Textblock using the BooleanToVisilityConverted included in the framework.

    And voila ! What do you think about this approach ?

  2. Karl Agius

    Said on March 3, 2009 :

    Hi Amit,

    What if you used a checkbox instead of a button to control whether the number should be shown? If the visibility is purely a UI thing, then you could use a setter to show/hide the TextBlock visibility based on the IsChecked property of the checkbox. I understand that your example is intentionally simple, so there are cases where this would not apply, but this should sort out most simple cases.

    In general, I prefer not to use events or commands unless the action actually initiaties a behaviour. In this case, the click toggles a property; if it was starting a calculation based on that number for example, then I’d go for an event/command/whatever.

    I totally agree with your desire to keep xaml and code behind clean! Have you looked at the Model-view-view-model (MVVM) pattern? If not, check it out, I’m sure you’ll like it :)

  3. Amit

    Said on March 3, 2009 :

    You are both Right, for this example.

    I also follow the put in in the XAML if possible approach but, I had times where the template was very complicated and involved alot of code you could not/ did not want to be in the XAML. In that case putting that code in a user control will make things alot easier.

  4. Sam

    Said on March 4, 2009 :

    Amit, the point of MVVM isn’t to not have code behind at all, is to use other patterns to achieve this. If you create a custom control, you will have to have your xaml in generics.xaml and the code behind inside the control so the only way to have the complex logic is to use, for example, commands, event manager, etc.

    This way your templates are not “bound” to your code behind by control names but the control or template will use binding to interact with its code behind which makes templating controls possible.

  5. Joel Cochran

    Said on March 4, 2009 :

    For something like this, I also prefer the ValueConverter approach. Relying on the Code Behind to make UI changes is the Windows Forms mentality. With the immense binding capabilities we have, most of these changes can be done without UserControls and without Code Behind.

    We really should reserve User Controls for when we need to modify the behavior of a control, or create a custom control. IMHO, UI effects and layout should be done with Templates and Styles as much as possible.

  6. Amit

    Said on March 5, 2009 :

    As I said this was only an example. I was talking about more complicated templates. Although You can still combine these solutions and use the XAML solution inside a UserControl.

    No harm in that… :)

  7. Sai

    Said on August 4, 2009 :

    Thanks for your solution, that help me finish my project. :)

  8. Pacquiao vs Mosley live stream

    Said on March 18, 2011 :

    your blog is very useful………

2 Trackback(s)

  1. May 25, 2009: Creating Gapped and Bulleted Shapes in WPF/Silverlight | Dev102.com
  2. Sep 6, 2009: WPF: 90+ Miejsc kt√≥re warto zna? « Dawid Po?li?ski

Post a Comment