#504 – GroupBox Basics

GroupBox is a control that draws a labeled border around a single child element.  Being a content control, it can contain at most one child element, but the child can be a panel control which in turn contains a number of other controls.

The GroupBox is typically used to show visually that a set of child controls are related.

The example below shows a GroupBox that contains a Grid as its child element.  The Grid then contains some Labels.

    <GroupBox Header="Dog Info" Margin="15">
        <Grid Margin="10">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0" Grid.Column="0" Content="Name:" FontWeight="Bold" HorizontalAlignment="Right"/>
            <Label Grid.Row="0" Grid.Column="1" Content="Kirby"/>
            <Label Grid.Row="1" Grid.Column="0" Content="Age:" FontWeight="Bold" HorizontalAlignment="Right"/>
            <Label Grid.Row="1" Grid.Column="1" Content="15" />
            <Label Grid.Row="2" Grid.Column="0" Content="Hobby:" FontWeight="Bold" HorizontalAlignment="Right"/>
            <Label Grid.Row="2" Grid.Column="1" Content="Chasing balls"/>
        </Grid>
    </GroupBox>

Advertisements

#503 – Be Careful When Casting RoutedEventArgs.Source

In an event handler, you’ll often cast the RoutedEventsArgs.Source property to a particular type.  When you have an event handler attached to a panel that can contain controls of various types, this can lead to problems.

In the example below, we’re assuming that the originator of the Click event is a Button.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button, sender is of type {1}",
                b.Content, sender.GetType().ToString()));
        }

If we have a panel that contains some Buttons, but also a ToggleButton control–which has a Click event but is not a Button–we get a crash when clicking on the ToggleButton.

A better solution is to check the type of the originator.

            if (e.Source is Button)
            {
                Button b = e.Source as Button;
                MessageBox.Show(string.Format("You clicked on {0} button, sender is of type {1}",
                    b.Content, sender.GetType().ToString()));
            }

#502 – Sender vs. RoutedEventArgs.Source

When handling a routed event, you can check the RoutedEventArgs.Source property to get at the control that is the originator of the event.  But the event handler also includes a sender parameter that in many cases also points to the originator of the event.

In the case of routed events, RoutedEventArgs.Source will refer to the originator of the event and sender will refer to the object that owns the event handler.

In the example below, RoutedEventArgs.Source will refer to the Button that a user clicked on, while sender will refer to the StackPanel to which the  Click event is attached.

    <StackPanel ButtonBase.Click="Button_Click">
        <Button Content="Keaton" />
        <Button Content="Chaplin" />
        <Button Content="Arbuckle" />
    </StackPanel>

 

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button, sender is of type {1}",
                b.Content, sender.GetType().ToString()));
        }

#501 – Sharing an Event Handler Across Multiple Controls, Method II

If you want to use an event handler to handle an event originating from several controls, you can specify the handler for each control and then use the RoutedEventArgs.Source property to determine the control that originated the event.

You can also just specify a handler for the Button.Click event on the parent panel that holds all of the buttons.  It will handle all Click events that originate lower down in the visual tree.

    <StackPanel ButtonBase.Click="Button_Click">
        <Button Content="Keaton" HorizontalAlignment="Center" Padding="10,5" Margin="5"/>
        <Button Content="Chaplin" HorizontalAlignment="Center" Padding="10,5" Margin="5"/>
        <Button Content="Arbuckle" HorizontalAlignment="Center" Padding="10,5" Margin="5"/>
    </StackPanel>

The event handler is the same as before–you can check the RoutedEventArgs.Source property to determine the Button that originated the event.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Get at originator of event using RoutedEventArgs.Source property

            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button", b.Content));
        }

#500 – Sharing an Event Handler Across Multiple Controls, Method 1

You can use the same event handler for more than one control by specifying the handler for each control and pointing to the same event handler code.

In the example below, we have three buttons, each of which wires up a handler for the Click event, but using the same handler (Button_Click).

    <StackPanel>
        <Button Content="Keaton" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
        <Button Content="Chaplin" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
        <Button Content="Arbuckle" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
    </StackPanel>

In the Button_Click event handler, we can check the Source property of the RoutedEventArgs parameter to determine which button sent us the event.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Get at originator of event using RoutedEventArgs.Source property

            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button", b.Content));
        }

#499 – Interacting with the Control That Initiated an Event

In WPF, you do not have to provide a name for every control in your user interface.  Since so much is accomplished through data binding, you often don’t need to interact with a control at all from your code.

But one scenario where you might want to interact with a control is from an event handler for an event that the control initiated.  Every event handler will have a sender argument that represents the control that fired the event.  You can cast this argument to the appropriate type to get at the original control.

<Button Content="Click Me" HorizontalAlignment="Center" Padding="10,5" Margin="10"
        Click="Button_Click"/>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            b.Width = b.ActualWidth + 1;
        }

No Post Today

2,000 Things / WPF is on hiatus today–back tomorrow.