BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Layout Controls - Canvas

The fourth part of the Windows Presentation Foundation Fundamentals tutorial begins an investigation of the layout controls. These are responsible for deciding how other controls are displayed. The first layout control is the Canvas.

IsEnabled Property

The IsEnabled property is similar to Enabled in Windows forms. If this Boolean property is set to false, the control becomes disabled and ignores user input. For some controls, the design changes to indicate a disabled state. For example, the text in a text box becomes "greyed out".

IsEnabled is a dependency property that is inherited by child controls. If you disable a Canvas, all of its child controls are disabled too.

<Canvas Background="Yellow" IsEnabled="False">

Name Property

The Name property applies a name to the control. This must meet the requirements of a .NET identifier. When defined, you can refer to the control from the code behind the window by name.

Modify the Canvas XAML as follows. We'll use the name from some C# code shortly.

<Canvas Background="Yellow" Name="MyCanvas">

Adding Child Controls

As with other layout controls, to add child controls you simply include the appropriate XAML within the Canvas element. To provide the Canvas with the required layout information, each child control can set values for four attached properties:

  • Left. Specifies the position of the left edge of a child control. The value is the number of pixels between the left edge of the control and the left edge of the Canvas.
  • Right. Specifies the position of the right edge of a child control. The value is the number of pixels between the right edge of the control and the right edge of the Canvas. This property has no effect if the Left property is set.
  • Top. Specifies the position of the top of a child control. The value is the number of pixels between the top edge of the control and the top of the Canvas.
  • Bottom. Specifies the position of the bottom of a child control. The value is the number of pixels between the bottom edge of the control and the bottom of the Canvas. This property has no effect if the Top property is set.

If none of the four properties are set, the child control will be placed in the default position at the top-left corner of the Canvas.

Let's add some Labels and text boxes to the Canvas. We'll look at these controls in detail later. For now, note the attached properties for the controls that determine their positions.

<Canvas Background="Yellow" Name="MyCanvas">
    <Label Content="First Name" Canvas.Left="10" Canvas.Top="10"/>
    <TextBox x:Name="FirstName" Height="23" Canvas.Left="105" Canvas.Top="13" Width="120"/>
    <Label Content="Last Name" Canvas.Left="10" Canvas.Top="40"/>
    <TextBox x:Name="LastName" Height="23" Canvas.Left="105" Canvas.Top="43" Width="120"/>
    <Button Content="OK" Canvas.Left="150" Canvas.Top="80" Width="75"/>
    <Button Content="Shift" Canvas.Left="60" Canvas.Top="80" Width="75"/>
</Canvas>

Running the program gives the following results:

WPF Canvas with child controls

Let's add a little code behind the design so that the form does something. Start by double-clicking the OK button in the designer. This adds a Click event handler to the button and switches to the code-behind so that you can add the functionality. As we didn't name the button, the event handler method has a default name. The code for the window's class will be similar to that shown below:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {

    }
}

If you switch back to the XAML you'll see that the Click handler has been linked automatically with the Click attribute.

<Button Content="OK" Canvas.Left="150" Canvas.Top="80" Width="75" Click="Button_Click_1"/>

Normally it would be a bad idea to use the default name for the method, as it promotes poor code readability. You can manually change it to a more appropriate name. If you do, remember to update the XAML to match.

We'll make the button display a message box containing the names from the text boxes. Add the following code before running the program to try it.

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    string msg = string.Format("Hello {0} {1}", FirstName.Text, LastName.Text);
    MessageBox.Show(msg);
}

Accessing Attached Properties from Code

In the above example we accessed properties of text boxes by name. The Text member is a dependency property that is wrapped in a CLR property. This makes it easy to read. When you want to access attached properties the process is different because the properties are not defined against the controls in question. We'll look at this in the final example in this article.

To retrieve the value of an attached property, you can call the child control's GetValue method. To specify which property you are interested in, you provide a DependencyProperty object. This is obtained from a static member of the parent control. For example, when reading the Left property from a Canvas's inner control, you pass that Canvas's LeftProperty member. The method returns an object that must be cast appropriately.

Setting the value uses a similar process. This time you call SetValue, passing the static property and the new value. If you wish to clear the value from an attached property, use the ClearValue method on the child control.

Double-click the Shift button in the designer and add the following code. This loops through all of the Canvas's child controls. For each control the Left property is read, the value incremented and the property is set to the higher value. This moves the controls to the right by one pixel for each click of the button.

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    foreach (FrameworkElement element in MyCanvas.Children)
    {
        double left = (double)element.GetValue(Canvas.LeftProperty);
        left++;
        element.SetValue(Canvas.LeftProperty, left);
    }
}

Try running the program and clicking the button to see the effect.

18 February 2013