The life of a code monkey

Text

Shadow Box in WPF Part 2

First of all,. if you have not read part 1, please go back and do so. I am only going to cover the changes needed to the window in part 1 to make the shadow box re-sizable.

Since the shadow box is being displayed within a grid, the easiest way to add re-sizing to it, is by utilizing the GridSplitter class. First we need to add some rows and columns to the _grdDialogContainer. 

<Grid.ColumnDefinitions>
    <ColumnDefinition Name="_colLeft"/>
    <ColumnDefinition Width="2"/>
    <ColumnDefinition Name="_colMid"/>
    <ColumnDefinition Width="2"/>
    <ColumnDefinition Name="_colRight"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
    <RowDefinition Name="_rowTop"/>
    <RowDefinition Height="2" />
    <RowDefinition Name="_rowMid"/>
    <RowDefinition Height="2" />
    <RowDefinition Name="_rowBottom"/>
</Grid.RowDefinitions>

I will get to the named columns and rows later when I go over the changes to the code-behind for the window. The non-named columns and rows are going to be used to hold the GridSplitters. 

On a quick side note. The reason for the specified widths and heights on these rows and columns was to counter an issue I was having where the cursor would not acknowledge that there was a GridSplitter present, even though it was perfectly visible. Setting the width/height to 1 or Auto is where I saw the issue. If anyone has a good explanation for this behavior (bug?) or better resolution I would be happy to hear it. 

Now that we have a place for the GridSplitters lets add them in.

<GridSplitter Grid.Row="2" Grid.Column="1" Width="1" HorizontalAlignment="Left" Background="{x:Static SystemColors.WindowFrameBrush}" ResizeBehavior="PreviousAndNext" />
<GridSplitter Grid.Row="1" Grid.Column="2" Height="1" VerticalAlignment="Top" Background="{x:Static SystemColors.WindowFrameBrush}" HorizontalAlignment="Stretch" ResizeBehavior="PreviousAndNext" />
<GridSplitter Grid.Row="2" Grid.Column="3" Width="1" HorizontalAlignment="Right" Background="{x:Static SystemColors.WindowFrameBrush}" ResizeBehavior="PreviousAndNext" />
<GridSplitter Grid.Row="3" Grid.Column="2" Height="1" VerticalAlignment="Bottom" Background="{x:Static SystemColors.WindowFrameBrush}" HorizontalAlignment="Stretch" ResizeBehavior="PreviousAndNext"/>

It is important to note that for the horizontal GridSplitters the HorizontalAlignment is required.

These splitters are taking the place of the Border control that was used in part 1. For those who are following along in the code, remove this control, but leave its child StackPanel. Finally we need to move a few of the attributes that were in the Border into the StackPanel (Grid positions and Background). The final result should look like this.

<StackPanel Grid.Row="2" Grid.Column="2" Background="{x:Static SystemColors.WindowBrush}" Name="_spContainer">
    <TextBlock Background="{x:Static SystemColors.ActiveCaptionBrush}" 
            Foreground="{x:Static SystemColors.ActiveCaptionTextBrush}" Name="_txtDialogTitle"
            Padding="4, 2, 2, 2" Visibility="{Binding Path=Text, Mode=OneWay, 
            Converter={StaticResource StringNotNullOrWhitespaceVisibilityConverter}, RelativeSource={RelativeSource Self}}" />
    <Grid Name="_grdDialog" MaxWidth="{Binding Width, ElementName=_grdDialogContainer}">

    </Grid>
</StackPanel>

The Border control did provide one nice feature that the GridSplitters are not handling. The corners around the dialog are missing.

 

To resolve this, add in four canvases to fill in the corners.

<Canvas Grid.Column="1" Grid.Row="1" Name="_canvasTopLeftCorner" Background="{x:Static SystemColors.WindowFrameBrush}"/>
<Canvas Grid.Column="3" Grid.Row="1" Name="_canvasTopRightCorner" Background="{x:Static SystemColors.WindowFrameBrush}"/>
<Canvas Grid.Column="3" Grid.Row="3" Name="_canvasBottomRightCorner" Background="{x:Static SystemColors.WindowFrameBrush}"/>
<Canvas Grid.Column="1" Grid.Row="3" Name="_canvasBottomLeftCorner" Background="{x:Static SystemColors.WindowFrameBrush}"/>

Now onto the code behind. Since most of the work is being handled by the GridSplitters there is only a couple changes that need to be made. Although only the code at the beginning and end of the method has changed I am including the entire method so that the flow is obvious.

private void showDialog(IShadowboxDialog argDialog, string argTitle = null)
{
    _colMid.MinWidth = 0;
    _rowMid.MinHeight = 0;
    _colLeft.Width = new GridLength(1, GridUnitType.Star);
    _colMid.Width = new GridLength(1, GridUnitType.Star);
    _colRight.Width = new GridLength(1, GridUnitType.Star);
    _rowTop.Height = new GridLength(1, GridUnitType.Star);
    _rowMid.Height = new GridLength(1, GridUnitType.Star);
    _rowBottom.Height = new GridLength(1, GridUnitType.Star);

    _grdMain.IsEnabled = false;
    _grdDialogContainer.Visibility = Visibility.Visible;
    _grdDialog.Children.Clear();
    _grdDialog.Children.Add((UIElement)argDialog);

    _txtDialogTitle.Text = argTitle;

    EventHandler closedHandler = null;
    closedHandler = (sender, e) =>
    {
        _grdMain.IsEnabled = true;
        _grdDialogContainer.Visibility = Visibility.Collapsed;
        _grdDialog.Children.Clear();

        argDialog.Close -= closedHandler;
    };
    argDialog.Close += closedHandler;

    var frameworkElement = (FrameworkElement)argDialog;

    RoutedEventHandler loadedHandler = null;
    loadedHandler = (sender, e) =>
        {
            frameworkElement.Loaded -= loadedHandler;

            _colMid.MinWidth = _spContainer.ActualWidth;
            _rowMid.MinHeight = _spContainer.ActualHeight;
        };

    frameworkElement.Loaded += loadedHandler;
}

Lets start at the end and work our way backwards through the method. The change to note is the self-unregistering loadedHandler. This event is raised and sets the minimum size for the row/column that contain the shadow box. This ensures that the entire shadow box is visible.

The next change seems obvious enough, at the top of the method the rows and columns are reset back to using the star width. This is required because GridSplitters will change the width/height properties to fixed pixel sizes when the user resizes the shadow box.  

Posted on Saturday, August 27 2011. Tagged with: CWPFDialogModla DialogModal WindowXAMLShadow BoxShadowBox
9
Notes
  1. interests69fty liked this
  2. kellylove90 liked this
  3. summer333444 liked this
  4. dotnetgeek posted this
Got a question or comment? Ask me.
Previous Next