May 24, 2014

WPF - Control Templates

Leave a Comment
In the previous post we have seen that, elements in the WPF object tree which derive from Visual constitute the visual tree. The visual tree is thus all the WPF elements that come together to render a control’s (or a set of controls’) UI to the screen. Control templates are XAML declarations of the visual tree of a control. Consider the simple case of a Button control,
 <!-- A default button -->
 <Button Height="100" Width="100" Content="Click Me!" />
</Grid>

The Button has a default visual template, i.e, a visual tree supplied by WPF. We want to override this implementation and provide our own custom UI for the button. To do this we’ll customize the Button control’s UI template (and thus it’s visual tree). This is simple enough,
<Grid>    
    <!-- A default button -->
        <Button Height="100" Width="100" Content="Click Me!">
            
            <!-- Override the Button's UI template -->
            <Button.Template>
                
                <!-- Create a new ControlTemplate that targets a Button -->
                <ControlTemplate TargetType="{x:Type Button}">

                    <!-- Override the default UI of the control with this custom UI -->
                    <Grid>
                        <Ellipse Height="100" Width="75" Stroke="Red" Fill="BlanchedAlmond" />
                        
                        <!-- Take the control's Content (which is “Click Me!”) and place here -->
                        <ContentPresenter Content="{TemplateBinding Content}" 
                           VerticalAlignment="Center" HorizontalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Button.Template>

        </Button>
</Grid>

As we can see from the XAML above, we’ve overridden the button’s UI template and provided our own implementation which consists of a Grid, with an Ellipse inside it and the Button’s Content inside the Ellipse. Even the height and width of the button get overridden to the new values of 100 and 75.
Default Button Custom Button

Another way to implement same thing is similar to the way we define styles in wpf, like below,
<Grid>
    <Grid.Resources>
        <!-- Define a named template, with a target type -->
        <ControlTemplate x:Key="RoundButtonTemplate" TargetType="{x:Type Button}">
            <!-- Override the default UI of the control with this custom UI -->
            <Grid>
                <Ellipse Height="100" Width="75" Stroke="Red" Fill="LightGray" />
                <!-- Take the control's Content and place here -->
                <ContentPresenter Content="{TemplateBinding Content}" 
                        VerticalAlignment="Center" HorizontalAlignment="Center" />
            </Grid>
        </ControlTemplate>
    </Grid.Resources>

    <!—- Apply the 'RoundButtonTemplate' template to this button -->
    <Button Height="100" Width="100" Content="Some Text"
            Template="{DynamicResource RoundButtonTemplate}" />

    </Grid>
Note that although we have overridden the UI, the button’s functionality remains the same, all the same events are raised and all the properties are still available. We should use TemplateBinding to allow the control to specify property values as much as possible. This is shown in XAML above for Content. Control templates also work with styles and triggers. The syntax is straightforward,
<Grid>
    <Grid.Resources>

        <!-- First ControlTemplate definition for normal button state UI -->
        <ControlTemplate x:Key="RoundButtonTemplate" TargetType="{x:Type Button}">
            <Grid>
                <Ellipse Height="60" Width="60" x:Name="MyEllipse"
                         Stroke="{TemplateBinding BorderBrush}"
                         Fill="{TemplateBinding Background}" />
                <ContentPresenter Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" />
            </Grid>
            <!-- Set a trigger to activate on mouseover -->
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="MyEllipse" Property="Fill" Value="Blue" />
                </Trigger>
            </ControlTemplate.Triggers>
         </ControlTemplate>

        <!-- Second ControlTemplate definition for clicked button state UI -–> 
        <ControlTemplate x:Key="RoundButtonPressedTemplate" TargetType="{x:Type Button}">
            <Grid>
                <Ellipse Height="60" Width="60"
                     Stroke="{TemplateBinding BorderBrush}"
                     Fill="Red" />
                <ContentPresenter Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" />
            </Grid>
        </ControlTemplate>

        <!-- Create a style definition for the button -->
        <Style x:Key="RoundButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Template" Value="{DynamicResource RoundButtonTemplate}"/>
            <Style.Triggers>
                <Trigger Property="IsPressed" Value="True">
                    <Setter Property="Template" Value="{DynamicResource RoundButtonPressedTemplate}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Grid.Resources>

    <!-- Apply the 'RoundButtonStyle' to this button -->
    <Button Height="100" Width="100" Content="Text"
            Style="{DynamicResource RoundButtonStyle}"
            BorderBrush="Red" Background="LightGray" />

</Grid>

The WPF content model allows the Button’s content to be a TREE of elements. In our examples, we have set the button’s content to “Click Me!” like this,

<Button Height="100" Width="75" Content="Click Me!" />

But the button’s Content could be set to a tree, like this,

<Button Height="100" Width="75">
    <Button.Content>
        <Grid>
            <StackPanel>
                <TextBlock Text="Click Me!"/>
            </StackPanel>
        </Grid>
    </Button.Content>
</Button>
Read More...

Sep 9, 2013

WPF - Logical and Visual trees

Leave a Comment
To be clear at the outset, there is only one object tree in WPF, which is created based on the nested relationships of the elements in the markup (the markup may be built via XAML or code). The logical and visual trees are two different ways of looking at this object tree. They are both subsets of the object tree.

When we’re creating some UI in XAML, for example,
<!-- Note: no x:Class, load this XAML using XmlReader.Create -->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="300" Height="300">
  <Grid>
        <Button Height="100" Width="100" Content="Text" />
    </Grid>
</Window>

You may intuitively think of a tree structure that looks like the one below (arrows point to parent). In reality, the object tree is far more complex and has many more elements. This simplified subset of the object tree, which most closely matches the elements declared in the XAML, is called the logical tree.
The elements in the object tree that derive from the Visual or Visual3D base class form the visual tree subset of the object tree. The visual tree consists of all the drawing primitives and other controls that are used to implement the UI. As you can see below, a lot more elements are included in the visual tree, even though you didn’t explicitly declare them (in the XAML above).
The way to read the tree diagram above is: the TextBlock’s visual parent’s type is ContentPresenter, while it’s logical parent is null. Both of ContentPresenter’s visual and logical parent’s types are ButtonChrome. ButtonChrome’s visual parent’s type is Button, while it’s logical parent is null, and so on.

The Button’s visual tree comprises of a TextBlock, a ContentPresenter, a ButtonChorme, and the Button itself.
Similarly, the Window’s visual tree comprises of a Border, an AdornerDecorator, a ContentPresenter, a Grid, and the Button along with it’s visual tree.

Setting visual properties on a visual parent propagates to visual descendants. For example, setting opacity, the IsEnabled property, or setting a transform on the parent applies to the children as well.

But why have two subsets of the full object tree? The purpose is that WPF uses the logical tree to iterate over child objects, propagate certain notifications, and also for resource lookup, and the visual tree to render visual objects, and for routed events.

WPF gives us a way to traverse both the logical and the visual trees using the LogicalTreeHelper and the VisualTreeHelper respectively. Using the these are simple enough,
// Traverse up the visual tree 
private void TraverseVisualTreeUp(DependencyObject element)
{
    while (element != null)
    {
        Console.WriteLine(element.GetType());
        element = VisualTreeHelper.GetParent(element);
    }
}
AND
// Traverse up the logical tree
private void TraverseLogicalTreeUp(DependencyObject element)
{
    while (element != null)
    {
        Console.WriteLine(element.GetType());
        element = LogicalTreeHelper.GetParent(element);
    }
}

The FrameworkElement.Parent property also returns the logical parent. Elements in the object tree that derive from the ContentElement base class show up in the logical tree but not in the visual tree.
Read More...

WPF - Dependency Properties

Leave a Comment
In .Net 1.1/2.0, a typical CLR property looks like this,
// Private field
private int _postId;

// Public property that wraps the private field
public int PostId{
    get { return _postId; }
    set { _postId= value; }
}

For a regular CLR property, the property value is read directly from a private class member. WPF introduces a new construct called a dependency property, which can get its value from different sources and the actual value resolution occurs dynamically at run-time based on some precedence rules.

For example, a TextBox‘s Text property, which is a dependency property, can get its value from a style, a trigger, an animation, or locally (among others). Consider the following XAML,
<Grid.Resources>
    <Style x:Key="TextBoxBaseStyle" TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Text" Value="Trigger setter text" />
            </Trigger>
        </Style.Triggers>
        <Setter Property="Text" Value="Property setter text" />
    </Style>
</Grid.Resources>

<!-- The local value of the Text property is set here -->
<TextBox x:Name="MyTextBox" Height="30" Width="100" 
    Text="Local value text" Style="{StaticResource TextBoxBaseStyle}" />

If we observe closely in above sample, the TextBox‘s Text (dependency) property is set in three places. So which one applies? If we run this, the TextBox starts out with the text "Local value text", even though we’ve set a Style that says Text should be "Property setter text". Why? This is because, when the WPF property system tried to resolve the Text value at run-time, the local value has precedence over a Style setter.

The precedence rules are (higher to lower),
  1. Active animations
  2. Local value
  3.  Style triggers
  4. Style setters
  5. Theme style
  6. Inheritance
  7. Default value (from dependency property metadata) 
As we have seen, a local value has higher precedence than a Style trigger or a Style setter. The Text dependency property depends on these different property value providers, each of which is checked in turn at run-time to get the property value. This also explains, how triggers are able to revert back the value when they are done. When the trigger stops changing the value, the WPF property system looks down the list for the next value provider that can supply a value; the trigger changes are thus temporary.

Now say we want to remove the dependency property’s local value so that the Text value can come from elsewhere (like a Style). The local value can be erased by,
this.MyTextBox.ClearValue(TextBox.TextProperty);
 
    // Note that these, will not remove the local value because
    // we're still setting a local value (to empty or null).
    //this.MyTextBox.Text = string.Empty;
    //this.MyTextBox.Text = null;

Once the local value is erased, you’ll see the Text changed to "Property setter text", and mouse over text to "Trigger setter text". Thus, the Text (dependency) property can get its value from different sources (local, style, trigger), and the run-time value depends a set of precedence rules. See the example, how to create dependency property?
// A dependency property is usually wrapped in a regular CLR property. This wrapper is not necessary,
// we can directly call GetValue/SetValue, but it’s useful if the dependency property needs to be set via XAML.
// Note that at runtime WPF calls the underlying GetValue/SetValue methods directly, bypassing the wrappers.
public int MyValue
{
    get { return (int)GetValue(MyValueProperty); }
    set { SetValue(MyValueProperty, value); }
}

// A dependency property definition
public static readonly DependencyProperty MyValueProperty =
            DependencyProperty.Register(
                "MyValue",              // Name of the dependency property
                typeof(int),            // Type of the dependency property
                typeof(MyClass),        // Type of the owner
                new PropertyMetadata(
                    0,                                            // The default value of the dependency property
                    new PropertyChangedCallback(OnValueChanged),  // Callback when the property changes
                    new CoerceValueCallback(CoerceValue)),        // Callback when value coercion is required
                new ValidateValueCallback(IsValidValue));     // Callback for custom validation

// The validation callback
private static bool IsValidValue(object value) { /* Validate the set value */ }
 
// The coercion callback
private static object CoerceValue(DependencyObject d, object value) { /* Adjust the value without throwing an exception */ }
 
// The value changed callback 
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ /* Called every time the dependency property value changes */ }

Dependency properties can also be read-only. A dependency property can only be created on a class which derives from the DependencyObject class, but since this class is very high up the WPF class hierarchy, this is not much of a concern.

Some of the advantages of dependency properties are,
  1. XAML friendly: Dependency properties can be set in XAML (via a CLR property wrapper) 
  2. Change notifications and validation: Get change notifications and validate property values by registering callbacks.
  3. Value inheritance: Dependency property values can be inherited from up the logical tree.
  4. Reduced memory: Since dependency properties are static, they save per-instance memory compared to regular CLR properties (which are based on per instance fields). 
We can also listen in to dependency property changes,
// We have to hook into TextBox’s Text property.
DependencyPropertyDescriptor textDescr = 
                  DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));
 
if (textDescr != null)
{
    textDescr.AddValueChanged(myTextBox, delegate
        {
            // Add your property changed logic here...
        });
}

Read More...

WPF - Triggers

Leave a Comment
In previous article, we learned Styles, Triggers are similar to styles, the difference is Styles are applied to controls unconditionally whereas Triggers as based on one or more conditions.

There are four types of Triggers,
  1. Property triggers are invoked when a dependency property changes. 
  2. Event triggers are invoked when a routed event is raised. 
  3. Data triggers are invoked when a regular .NET property changes. 
  4. Multi triggers (and MultiData triggers) represent a logical AND relationship between triggers.
1. Property triggers: A property trigger executes a collection of Setters when a specific dependency property changes to a specific value. When the dependency property no longer has the specified value, the Setters are undone with no additional code required.

For example, if we want to change the background of a TextBox, when it is moused-over we can simply do this,
<Grid>
    <Grid.Resources>
        <!-- Define a named style... -->
        <Style x:Key="TextBoxBaseStyle">
            <!-- with a triggers collection... -->
            <Style.Triggers>
                <!-- and a property trigger – when the textbox is moused-over... -->
                <Trigger Property="TextBox.IsMouseOver" Value="True">
                    <!-- set the background undefinedcolor) property  to LightGray -->
                    <Setter Property="TextBox.Background" Value="LightGray" />
                </Trigger>
                <!-- Note that we don’t have to define a property trigger for when 
                IsMouseOver is false, this is automatically handled by the framework -->
            </Style.Triggers>
            <!-- These Setters are not triggered by a dependency property --> 
            <Setter Property="Control.Height" Value="30" />
            <Setter Property="Control.Width" Value="60" />
        </Style>
    </Grid.Resources>

    <!-- Apply the style to this textbox -->
    <TextBox Style="{StaticResource TextBoxBaseStyle}" />
</Grid>

2. Event triggers: An event trigger executes a collection of Setters when a routed event is raised. Starting an animation is the most common action for an event trigger.
<Grid>
    <Grid.Resources>
        <!-- Define a named style... -->
        <Style x:Key="TextBoxBaseStyle">
            <!-- with a triggers collection -->
            <Style.Triggers>
                <!-- Define an event trigger that fires on mouseenter... -->
                <EventTrigger RoutedEvent="TextBox.MouseEnter">
                    <BeginStoryboard Storyboard="{StaticResource BeginAnimation}" />
                </EventTrigger>
                <!-- and another event trigger which fires on mouseleave -->
                <EventTrigger RoutedEvent="TextBox.MouseLeave">
                    <BeginStoryboard Storyboard="{StaticResource EndAnimation}" />
                </EventTrigger>
            </Style.Triggers>
            <!-- These Setters are not triggered by an event –>
            <Setter Property="Control.Height" Value="30" />
            <Setter Property="Control.Width" Value="60" />
        </Style>
        <Storyboard x:Key="BeginAnimation">
            <!-- In this animation we'll change the background's color property -->
            <ColorAnimation 
                Storyboard.TargetProperty="undefinedTextBox.Background).undefinedSolidColorBrush.Color)" 
                To="LightGray" Duration="0:0:0.1"/>
        </Storyboard>
        <Storyboard x:Key="EndAnimation">
            <!-- In this animation we'll change the background's color property -->
            <ColorAnimation 
                Storyboard.TargetProperty="undefinedTextBox.Background).undefinedSolidColorBrush.Color)" 
                To="White" Duration="0:0:0.1"/>
        </Storyboard>
    </Grid.Resources>

    <!-- Apply the style to this textbox -->
    <TextBox Style="{StaticResource TextBoxBaseStyle}" />
</Grid>

3. Data Triggers: Similar to Property triggers except that any .NET property can invoke these. Note that the Setters are still restricted to setting dependency properties.
<Grid>
    <Grid.Resources>
        <!-- Define a named style... -->
        <Style x:Key="TextBoxBaseStyle">
            <!-- with a triggers collection... -->
            <Style.Triggers>
                <!-- Define a data trigger that fires when the Role property is set to Admin -->
                <DataTrigger Binding="{Binding Path=Role}" Value="Admin">
                    <Setter Property="TextBox.Foreground" Value="Red" />
                </DataTrigger>
            </Style.Triggers>
            <Setter Property="Control.Height" Value="30" />
            <Setter Property="Control.Width" Value="60" />
        </Style>
    </Grid.Resources>

    <!-- Apply the style to this textbox -->
    <TextBox x:Name="MyTextBox" Style="{StaticResource TextBoxBaseStyle}" />
</Grid>

AND in the code behind,
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
 
        // When the role is Admin the foreground text will be red colored.
        this.MyTextBox.DataContext = new Person { Role = "Admin" };

        // Otherwise the foreground text color is default (black)
        //this.MyTextBox.DataContext = new Person { Role = "User" };
    }
}

public class Person
{
    public string Role { get; set; }
}

4. Multi triggers (and MultiData triggers): Since Style.Triggers can contain multiple triggers, if we have the exact same Setters then a logical OR relationship forms between them.

This means that, “If IsMouseOver is true OR if IsFocused is true – set Background color to Red”. Correspondingly, a logical AND relationship is expressed using a Multi trigger (or MultiData trigger).
<Style.Triggers>
    <MultiTrigger>
        <MultiTrigger.Conditions>
            <Condition Property="TextBox.IsMouseOver" Value="True" />
            <!-- AND -->
            <Condition Property="TextBox.IsFocused" Value="True" />
        </MultiTrigger.Conditions>
        <Setter Property="TextBox.Background" Value="Red" />
     </MultiTrigger>
</Style.Triggers>

Read More...

Sep 8, 2013

WPF - Styles

Leave a Comment
A style in WPF is the collection of (dependency) properties that affect the appearance and behavior of a control. For example, the text color inside a TextBox and background of a Button. For our examples, say we’re trying to affect the styles of two textBoxes,

<Grid x:Name="MyGrid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
                
    <TextBox Grid.Column="0" />
    <TextBox Grid.Column="1" />
</Grid>

Since the textBoxes don’t have a height and width, lets use a named style to set them.
<Grid.Resources>
    <Style x:Key="TextBoxBaseStyle"> <!—- Named style (because we defined an x:Key) -–>
        <!—- Property=”[ClassName].[DependencyProperty]” -–> 
        <Setter Property="Control.Height" Value="30" />
        <Setter Property="Control.Width" Value="60" />
    </Style>
</Grid.Resources>

We need to explicitly apply this style to all the textBoxes,
<!—- Both textboxes need to explicitly set the Style properties --> 
<TextBox Grid.Column="0" Style="{StaticResource TextBoxBaseStyle}" />
<TextBox Grid.Column="1" Style="{StaticResource TextBoxBaseStyle}" />

Now all the textboxes have the same height and width. We can override a style by declaring the property on the control.
<TextBox Grid.Column="0" Style="{StaticResource TextBoxBaseStyle}" />
<!—- Override the Height property -->
<TextBox Grid.Column="1" Height="60" Style="{StaticResource TextBoxBaseStyle}" />

The style we defined (“TextBoxBaseStyle”) can be applied to any type, for example Button,
<Button Grid.Column="2" Style="{StaticResource TextBoxBaseStyle}" />

We can do this because the style implicitly targets Control types. If we want to target a particular type, we can use the TargetType property.
<!—- This style will only target TextBox and TextBox’s derived types -->
<Style x:Key="TextBoxBaseStyle" TargetType="TextBox">
    <Setter Property="Control.Height" Value="30" />
    <Setter Property="Control.Width" Value="60" />
</Style>

If we do this, we’ll no longer be able to apply this style to a Button, but we can apply the style to TextBox derived types. Since the style’s target type is TextBox we can set properties that are specific to a TextBox,
<Style x:Key="TextBoxBaseStyle" TargetType="TextBox">
    <Setter Property="Control.Height" Value="30" />
    <Setter Property="Control.Width" Value="60" />
    <!—- TextBox specific property -–>
    <Setter Property="TextBox.IsReadOnly" Value="True" />
</Style>

Also, we could hook into events via an EventSetter.
<Style x:Key="TextBoxBaseStyle" TargetType="TextBox">
    <Setter Property="Control.Height" Value="30" />
    <Setter Property="Control.Width" Value="60" />
    <Setter Property="TextBox.IsReadOnly" Value="True" />
    <!—- Write any custom code in the handler: void OnMouseEnter(object sender, RoutedEventArgs args) -–>
    <EventSetter Event="MouseEnter" Handler="OnMouseEnter" />
</Style>

We can create a typed style and give all the TextBoxes (in the scope of the style) the same properties. This is the whole point of having styles – to define a style once and have multiple controls share it. To create a typed style we need to get rid of the x:Key,
<Grid.Resources>
    <Style TargetType="TextBox"> <!—- This typed style applies to all textboxes within its scope -–>
                                 <!—- but not TextBox derived types -–> 
        <Setter Property="Control.Height" Value="30" />
        <Setter Property="Control.Width" Value="60" />
        <Setter Property="TextBox.IsReadOnly" Value="True" />
        <EventSetter Event="MouseEnter" Handler="OnMouseEnter" /> 
    </Style>
</Grid.Resources>
<TextBox Grid.Column="0" />
<TextBox Grid.Column="1" Height="60" />

But a typed style only applies to the declared type and not derived types (note the difference with a named type). Styles can also derive from other (named) styles,
<Grid.Resources>
    <Style x:Key="TextBoxBaseStyle">
        <Setter Property="Control.Height" Value="30" />
        <Setter Property="Control.Width" Value="60" />
    </Style>
    <Style x:Key="TextBoxDerivedStyle" TargetType="TextBox" BasedOn="{StaticResource TextBoxBaseStyle}">
        <Setter Property="TextBox.IsReadOnly" Value="True" />
    </Style>
</Grid.Resources>
        
<TextBox Grid.Column="0" Style="{StaticResource TextBoxBaseStyle}"/>
<TextBox Grid.Column="1" Height="60" Style="{StaticResource TextBoxDerivedStyle}"/>

And styles can have their own resources,
<Style x:Key="TextBoxDerivedStyle" TargetType="TextBox" BasedOn="{StaticResource TextBoxBaseStyle}">
    <Style.Resources>
        <SolidColorBrush x:Key="TextBoxBackgroundColor" Color="LightGray" />
    </Style.Resources>
    <Setter Property="TextBox.IsReadOnly" Value="True" />
    <Setter Property="TextBox.Background" Value="{StaticResource TextBoxBackgroundColor}" />
</Style>

Of course we can do all this in code programmatically as shown below,
Style textboxStyle = new Style();
textboxStyle.TargetType = typeof(TextBox);

Setter backgroundSetter = new Setter(TextBox.BackgroundProperty, Brushes.LightGray);            
textboxStyle.Setters.Add(backgroundSetter);

this.MyTextBox.Style = textboxStyle;

OR if the style is already defined in XAML,we can do like this,
this.MyTextBox.Style = (Style)this.MyGrid.FindResource("TextBoxDerivedStyle");

Read More...