Improve Your Technology

Just another blog for techology

WPF and XAML Conventions

WPF and XAML Conventions

XAML Conventions

XAML is still XML and so the majority of the XML formatting standards that you use will still apply. That said, here’s a couple of extra ones I’ll throw in on top:

1. Use x:Name instead of Name

While they both do the same thing, Name can only be used for some elements, where x:Name will work for any element (except elements in a resource dictionary). When you’re looking through a long list of attributes on an element, attributes starting with an “x:” prefix tend to be a little easier to spot. To make it easy to find the name of an element without looking twice, I always stick to x:Name.

2. Place the first attribute of an element on the line underneath the element name

This rule exists because XML editors will generally indent each line to match up with the first attribute, and elements with different names thus end up with an odd-looking amount of whitespace. For example:

<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"
            Margin="3"
            Background="{TemplateBinding Background}">
    <Button Content="Hello" 
            Background="{StaticResource Brush_ButtonBackground}"
            Width="300" />
    <ImageButton Source="{StaticResource Image_Copy}"
                 Width="16"
                 Height="16" />

The XML element names denote the level of nesting by their indentation, but the XML attributes do not line up correctly, which creates whitespace which detracts from seeing the natural layout. This gets worse the more lines of attributes specified or the longer the XML element names.

Change them so that the first attribute is on a new line, and put the closing angle bracket on its own line as well, like this:

<StackPanel 
    DockPanel.Dock="Top" Orientation="Horizontal"
    Margin="3"
    Background="{TemplateBinding Background}"
    >
    <Button 
        Content="Hello" 
        Background="{StaticResource Brush_ButtonBackground}"
        Width="300" 
        />
    <ImageButton 
        Source="{StaticResource Image_Copy}"
        Width="16"
        Height="16" 
        />

This places all of your attributes at the same standard indentation level, and stops them from being more indented than their child elements. The nesting of the attibutes now compliments the nesting of the elements.

3. Prefer StaticResource over DynamicResource

The differences between {StaticResource } and {DynamicResource } are documented on MSDN. Your team should know and when to correctly use each, and StaticResource should generally be the default. However, tools such as Blend have a natural tendency to insert DynamicResource, and fighting the tools generally isn’t a good idea, so this is a preference more than a rule.

4. Use SnapsToDevicePixels where appropriate

This MSDN article explains it. If you declare, for example, a Border with a 1-pixel thick edge around it, the WPF rendering engine may sometimes smooth it, drawing it half over one pixel and half over the other. While this is often great for many shapes, on a 96 DPI monitor it can stand out and often makes the element look out of the ordinary. Consider creating a Style resource that sets this property automatically for all Border elements.

5. Prefer binding to code-behind over setting DataContext explicitly

From a XAML file’s code behind it is possible to push values into the DataContext, for example:

public class PreferencesDialog 
{
    public PreferencesDialog(UserPreferences prefs) 
    {
        InitializeComponent(); 
        DataContext = prefs;
    }
}

As a view evolves you begin to use multiple sources for data, and you suddenly begin setting the DataContext’s of specific elements in the XAML, which creates some assumptions on the layout and structure of the XAML and can break the designer/developer workflow.

An alternative is the following:

public class PreferencesDialog 
{
    public static readonly DependencyProperty PreferencesProperty = DependencyProperty.Register(...);
    
    public PreferencesDialog(UserPreferences prefs) 
    {
        InitializeComponent();
        Preferences = prefs;
    }

    public UserPreferences Preferences
    {
        get { return (UserPreferences)GetValue(PreferencesProperty); }
        set { SetValue(PreferencesProperty); }
    }
}

With the corresponding XAML:

<Window 
    x:Name="This"
    DataContext="{Binding ElementName=This}"

This reduces your code-behind’s expectations about the XAML file’s structure, and makes any property on code-behind a candidate for data binding.

6. Pick a Naming Convention for Elements

When you apply an x:Name to an element, try to be consistent. For elements in a ControlTemplate, PART_Something is the standard for elements that have special meaning to the control the template applies to. For everything other element, a prefix of “_”, or camel cased names, or pascal cased names, is generally good enough. And as with any variable, naming is important, so please, no elements named “n” or “foo” or “border1” 🙂

7. Prefer to merge resources at the Application level

When using merged resource dictionaries, it can be tempted to reference the resource XAML files from each Window rather than at the root Application XAML file. This happens especially often when using controls declared in seperate projects, since tools such as Blend tend to add the resource file links automatically. What then happens is that each time the object is instantiated, the resources are completely loaded again, even if they already exist higher in the tree (remember that the Resources property is a dictionary, so items within the same dictionaries are merged, but there is no such thing as “dictionary inheritance”). In some cases, this can lead to large amounts of memory usage and slow loading times.

8. Use DependencyProperties on DependencyObjects

When you have user controls of other objects that derive from DependencyObject, use DependencyProperties instead of normal CLR properties an INotifyPropertyChanged. This creates no confusion as to how properties should be monitored.

Resource Organization

As your WPF projects grow larger, you’re going to start to get a lot of resources and you’ll need to move them out of “App.xaml”. But how do you organize them?

1. Structuring Resources

You can split XAML files into two general types:

  • Functional XAML files – for example, Windows, User Controls, or Pages
  • Resource XAML files – Resource Dictionaries or your App.xaml file

Resource XAML files can be subdivided even further:

  • Generic Resource XAML files – these contain things that are used throughout the application. Brushes, ImageSources, some Styles and Converters are good candidates here.
  • Specific Resource XAML files – these contain resources for a specific Windows, Controls or Pages.

You’re probably aware that you can put resources within the XAML of Functional XAML files, such as in a Window.Resources element. This works well as a starting point, but eventually data templates and specific styles can become quite large. Instead, you may find it easier to move the specific styles and resources for a given Window or User Control into it’s own XAML file. This way, my “MainWindow.xaml” might define the structure of the Window, while “MainWindowResources.xaml” might contain the styles and resources that are specific to that Window but won’t clutter up the structural markup.

 

An example project structure could look something like this:

  • WpfBankingApplication/
    • /Shared/ – a folder that contains resources shared throughout the entire application
      • /Converters/ – a folder that contains a list of generic C# IValueConverters, such as a DateTime formatting converter or a string formatting converter
      • /Images/ – contains all the raw image files (.PNG, etc.)
      • /BrushResources.xaml – solid brushes, linear gradient brushes and drawing brushes
      • /ConverterResources.xaml – allows us to reference any of the converters by merging our resource dictionary with this file, rather than re-declaring our converters every time
      • /ImageResources.xaml – as above, allows us to declare an ImageSource once and reference it from anywhere.  
      • /TextResources.xaml – styles applied to textual elements (Hyperlinks, TextBlocks, etc.)
      • /ControlResources.xaml – styles applied to specific types of controls, like perhaps custom-skinned Buttons or TextBoxes.
    • /HomeLoans/ – folder for the “home loans”-specific functionality of the application
      • /HomeLoanEntryWindow.xaml – a functional XAML file with the structural definition of the Home Loan Entry window.
      • /HomeLoanEntryWindowResources.xaml – a resource XAML file with the styles, control templates, custom brushes and other resources used by the Home Loans Entry window.

This structure keeps all of our XAML files small, and makes it pretty obvious to developers where they should place bits of functionality. Aim to keep each XAML file to less than a couple of hundred lines of XAML – 400 lines is probably a good rule of thumb. If they go beyond that, it’s probably time to split them up again.

2. Resource Naming Conventions

The biggest issue with using multiple resource XAML files is figuring out where a specific style or resource comes from. In C#, we can move our mouse over a type name and Visual Studio will tell us where the class is defined, and we can even right-click it and “Go to definition…” in order to go right to it. Unfortunately, the same can’t be done with things in XAML, though that’s a good idea for an add-in 🙂

To aid in figuring out where something comes from, employ a naming convention. The rules are simple. Notice in the project structure above that all of the Resource XAML files are suffixed with “Resources.xaml”.

1.        Any resources or styles declared in an “XYZResources.xaml” file gets a prefix of “XYZ_”. So, if we declare standard light blue SolidColorBrush in BrushResources.xaml, we name it “Brush_LightBlue“. This means if you ever see markup like this:

2.              <TextBlock 
    Style="{StaticResource Text_ContentHeaderText}"
3.                  Margin="3"
4.                  >
5.                  Welcome!
</TextBlock>

You’ll know precisely where it comes from.

6.        Any resources or styles declared in a Functional XAML file, such as “HomeLoansEntryWindow.xaml“, gets a prefix of “Local_“. This is because these resources won’t be referred to outside of the XAML file they’re declared in, so if you spot the “Local_” prefix you can interpret it as “in this file“.

7.              <TextBlock 
    Style="{StaticResource Local_ContentHeaderText}"
8.                  Margin="3"
9.                  >
10.               Welcome!
</TextBlock>

 

Ref link: http://groups.google.com.au/group/wpf-disciples/web/wpf-and-xaml-coding-guidelines

Advertisements

December 13, 2008 Posted by | Technology, WPF and XAML Conventions | , | Leave a comment