Archive for the ‘ WPF ’ Category

WPF Series: Adorners, Commands and Logical Tree


Today I’m going to tell you a WPF story. But before I start to dig deeper let me first introduce you the main characters in this post. Here they are:
Adorner – adorners are simple UIElement decorators. Suppose that you have a RichTextBox and you want to place a comment box over it, so that users can comment on the text in the box. This can be archived with adorners. Actually the WPF framework uses adorners internally for exactly the same purpose when you edit and annotate FlowDocument in a DocumentViewer. This is the reason why adorners are in System.Windows.Documents namespace.
Command – commands are UI flavored implementation of the command pattern in WPF. You can read about them here.
Logical Tree – There are two control trees in WPF. One is the visual one, the other is the logical one. Imagine a Button for example. The button as logical entity act as a single control, you can click on it etc. However the visual representation of the button contains different UIElements – borders, TextBlock, etc. This means that WPF should maintain two separate control trees, one for the behavior elements – logical tree and one for the visual representation – visual tree. More info here.

There are a bunch of WPF adorners samples out there (including the SDK ones as well). But as usual when you try to create something more complex the standard samples break down. For example let say that we want to achieve something like the mini toolbar in Word 2007:

Let’s start our quest with a TextBox that look like this:

and you want to put a simple button next to it that will let say will open a hyperlink that is somehow related to the TextBox. You could easily achieve this with adorners and end up with something which look like this:

How to do this? You could create something like TextBoxAdorner that will derive from Adorner and will look like this:

public class TextBoxAdorner : Adorner
{
    private readonly UIElement adorningElement;

    public TextBoxAdorner(TextBox textBox, UIElement adorningElement ) : base( textBox )
    {
        this.adorningElement = adorningElement;

        if (adorningElement != null)
        {
            AddVisualChild(adorningElement);
        }
    }

    protected override int VisualChildrenCount
    {
        get { return adorningElement == null ? 0 : 1; }
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        if (adorningElement != null)
        {
            Point adorningPoint = new Point();

            //position at the end of the text box
            adorningPoint.X = ((TextBox)AdornedElement).ActualWidth;

            //position above the text box
            adorningPoint.Y -= adorningElement.DesiredSize.Height;

            adorningElement.Arrange( new Rect( adorningPoint, adorningElement.DesiredSize ) );
        }
        return finalSize;
    }

    protected override Visual GetVisualChild(int index)
    {
        if (index == 0 && adorningElement != null)
        {
            return adorningElement;
        }
        return base.GetVisualChild(index);
    }
}

Note that we call AddVisualChild() method so that the element that is passed to the constructor will be visible. It is also necessary VisualChildrenCount to return count of 1 and GetVisualChild() to return the UIElementthat is added to the visual tree – in our case this is the adorningElement.

So far so good. Now imagine that the button that is added as adorner did not have a click handler, but have a command set. Let’s name the command – “NavigateToLink”. The command handler is added to TextBox‘s input bindings, because the TextBox itself “knows” how to execute “NavigateToLink” command. (The sample is with TextBox, but you could imagine have your own custom control that have that logic in it). But what happens when we do this:

As you can see the button is disabled, because the command infrastructure in WPF did not manage to find a handler for our “NavigateToLink” command. This causes the Button to become disabled. Now what?

If you refer to the command readings in the links that were in the beginning of the post you will find our that the command mechanism in WPF uses the logical tree of controls to find handlers for particular commands. This bring us to point where we added the Button to visual tree. In our case we will have to add it as a logical child of the TextBox as well. This will automatically add it the logical tree of controls and the command handler will be correctly resolved and the Button enabled. Here is the new constructor of TextBoxAdornerclass:

public TextBoxAdorner(TextBox textBox, UIElement adorningElement ) : base( textBox )
{
    this.adorningElement = adorningElement;

    if (adorningElement != null)
    {
        AddVisualChild(adorningElement);
        textBox.AddLogicalChild( adorningElement );
    }
}

Here comes the other problem. For encapsulation reasons the AddLogicalChild() method ofFrameworkElement is marked as protected internal and can not be called as we call it in the snippet above. One way to workaround this is to derive from TextBox and make the method internal for your assembly. The other way is to use reflection and call the method. You can even create an extension method that will be available for all FrameworkElements. To make it even more extreme you can use expression trees to cache the method call and optimize the reflection. Here is the code:

internal static class FrameworkElementExtensions
{
    private static readonly Action AddLogicalChildMethod = CreateAddLogicalChildMethod();

    private static Action CreateAddLogicalChildMethod()
    {
        ParameterExpression instance = Expression.Parameter( typeof ( FrameworkElement ), "element" );
        ParameterExpression parameter = Expression.Parameter( typeof ( object ), "child" );

        MethodInfo methodInfo = typeof ( FrameworkElement ).GetMethod(
            "AddLogicalChild", BindingFlags.NonPublic | BindingFlags.Instance );
        MethodCallExpression method = Expression.Call( instance, methodInfo, parameter );

        Expression> lambda =
            Expression.Lambda>( method, instance, parameter );

        return lambda.Compile();
    }

    internal static void AddLogicalChild( this FrameworkElement element, object child )
    {
        AddLogicalChildMethod( element, child );
    }
}
Advertisements

What is WPF?


Often we see movies/TV Serious that use software application with extraordinary user interfaces. An example of such a TV serious would be CSI. The first time I saw an episode I was impressed with the software that these guys were using. Controls unfolding, three-dimensional pages spinning, wow these guys are lucky to have such software applications….

Well Guys hold on to your rotating chairs because finally we can do CSI-like UI’s thanks to Microsoft with the mighty WPF.

Windows Presentation Foundation aka Avolon is a major component of .Net Framework 3.0. This technology can be used in two different ways;

In code (like normal Widows Forms)
In XAML (pronounced zammel), HTML like code.

Before WPF one could compare a Designer-Developer relation to a Cat-Dog relation. Reason being the designer dreams of controls that are easy to design with tools as Photoshop yet for the developer to implement these controls, a lot of effort is required. WPF is the answer to every developer’s prayer. Designers now can dream, dream and dream since they will be building the user interface using tools such as Microsoft Expression to generate the XAML for us developers.

Enough with the talk; let’s do some action. We will build a normal button with both C# code and XAML.

C# Code

Button b = new Button();

b.Content = “Hello World”;

XAML

< button xmlns=”http://schemas.microsft.com/winfx/2006/xaml/presentation”>
Hello World < /button>

Both of the above code lines will emit the same output i.e. a normal button with the text Hello World. Now lets take this button up a level using one of WPF features; Control Templates.

<Window.Resources>

<ControlTemplate x:Key=“maltaDevButton“ TargetType=“{x:Type Button}“>

<Grid>

<Ellipse x:Name=“outerCircle“ Width=“100“ Height=“100“>

<Ellipse.Fill>

<LinearGradientBrush StartPoint=“0,0“ EndPoint=“0,1“>

<GradientStop Offset=“0“ Color=“Blue“/>

<GradientStop Offset=“1“ Color=“Red“/>

</LinearGradientBrush>

</Ellipse.Fill>

</Ellipse>

<Viewbox>

<ContentControl Margin=“10“ Content=“{TemplateBinding Content}“ />

</Viewbox>

</Grid>

<ControlTemplate.Triggers>

<Trigger Property=“IsMouseOver“ Value=“True“>

<Setter TargetName=“outerCircle“ Property=“Fill“ Value=“Orange“/>

</Trigger>

</ControlTemplate.Triggers>

</ControlTemplate>

</Window.Resources>

<Grid>

<Button Width=“100“ Height=“100“ FontSize=“10“ Template=“{StaticResource maltaDevButton}“Content=“Malta Dev“ />

</Grid>

Control templates are only one of the features that WPF offers. WPF offers a lot of other things such as

Data Binding
You can bind a control to a collection of data just like in normal windows forms yet with WPF if something in the control changes the UI will update automatically (This is available if the collection is ObservableCollection, or if the Collection being bound implements the INotifyCollectionChange or the INotifyPropertyChange)
Animations
You can have animations just like in Macromedia Flash
Rich Content support for all controls
Example: A drop down list that contains images as list items.
Smooth fonts
Since WPF uses vector graphics fonts are not effected when you resize the form.
You can also create you own fonts and embed them in your application as a resource
Full support for documents
Example: You can have a document in a form that flows respectively when the form is resized
Bitmap effects
You can have effects such as blur, shadow, reflection etc on controls.
Integrated video support
You can have a video playing in your form and overlay controls on the video.
Style an application
You can have a predefined style that sets all controls in the application (like CSS for HTML)

The image below is a screen shot of an application developed with WPF. You can download all source code of this application from wpf.netfx.com/files/default.aspx

WPF Dialogs and DialogResult


In WPF Dialogs are quite different from Windows Forms. The behavior is still the same i.e when you have a Dialog opened (by calling the ShowDialog() method) the user must close the dialog in order to use the Window that opened the Dialog Window. The difference is the way you handle the Dialog Result and also how to set Dialog Results.

Let’s say that you created a Window in Windows Forms and you have a Button. You can set the DialogResult property of the button so that when the user click on that button the Dialog ends with the Dialog Result that you have set. (also if the user clicks the exit button of the Dialog the DialogResult would be a Cancel). The code to handle the DialogResult in Windows Forms would look like this.

1: DialogResult result = new Form1().ShowDialog();
   2: if (result == DialogResult.OK)
   3:     MessageBox.Show("User clicked OK");
   4: else if (result == DialogResult.Cancel)
   5:     MessageBox.Show("User clicked Cancel");

In the WPF this is different. There is no DialogResult property on controls and also the ShowDialog does not return a DialogResult instead it returns a Nullable<bool>.

So to handle a DialogResult after calling the ShowDialog() in WPF your code would look like this:

1: MyDialog dialog = new MyDialog();
   2: dialog.ShowDialog();
   3:
   4: if (dialog.DialogResult.HasValue && dialog.DialogResult.Value)
   5:     MessageBox.Show("User clicked OK");
   6: else
   7:     MessageBox.Show("User clicked Cancel");

ShowDialog can return True which is equivalent to DialogResult.Ok or False which is equivalent to DialogResult.Cancel.

So let’s have a look at how you can create a Dialog in WPF and set the DialogResult of the Dialog. We can do this by setting a property on the Window called DialogResult. Once you set this property on the Window the Window will automatically close and the ShowDialog methods returns the result that you have set in the DialogResult property.

If you want to have a “Cancel” Button for your Dialog you can use the IsCancel property and set this to true. When the user clicks the button the DialogResult will be set to false and the Dialog will close. This will also allow the user to click ESC to cancel the dialog ( which is something that every user would expect from a dialog). Please note that if you have more than one button with the IsCancel = “True” the ESC does not work as expected instead the focus will be given to the first button that has the IsCancel = “True”. The XAML for this button would look like this:

 1: <Button Width="100" Content="Cancel" IsCancel="True"/>

If you want to have an “Ok” button you can set the IsDefault property. This property will NOT set the DialogResult to true for you, instead it will allow the user to click “Enter” and the Click event handler of the button is automatically called (so as such it doesn’t really have to do with Dialogs, it is just more useful when you are using Dialogs because users would expect such a behavior). You must code the event handler (and obviously register the handler to the click event) yourself and set the DialogResult to true. Something like this.

1: private void ButtonOkClick(object sender, RoutedEventArgs e)
   2: {
   3:     DialogResult = true;
   4: }

For more information visit: MSDN documentation on this here.