Skip Ribbon Commands
Skip to main content

Blog

:

Quick Launch

Home
Blog of Christopher Vigna, containing my thoughts, comments and questions.
June 04
Fun with GridSplitter

Another control I’ve been playing with is the <GridSplitter />.  The grid splitter control allows a user to resize a column or row to their liking.

Below is a basic grid with two columns taking up the same amount of space. A gridsplitter is put on the right side of the first column to allow the user to resize it.

   <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Rectangle Grid.Column="0" Fill="Green" />
    <Rectangle Grid.Column="1" Fill="Red" />
    <GridSplitter Grid.Column="0" Width="5" HorizontalAlignment="Right" VerticalAlignment="Stretch" Background="Black" />
  </Grid>

Click to go to a live demo.

The gridsplitter control uses the HorizontalAlignment and VerticalAlignment properties to determine the movement direction. The MSDN article has a nice table which describes the effect of the various property values:

GridSplitter type HorizontalAlignment value VerticalAlignment value
Resizes rows Stretch Top, Bottom, Center
Resizes columns Left, Right, Center Stretch
If ActualHeight is greater than or equal to ActualWidth, this resizes the columns. If ActualHeight is less than ActualWidth, this resizes the rows. Stretch Stretch


Here is a little more complex grid with three columns and two gridsplitters. Notice the gridsplitters are always put on the border of two columns. Splitters put on an outside border do nothing.

   <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Rectangle Grid.Column="0" Fill="Green" />
    <Rectangle Grid.Column="1" Fill="White" />
    <Rectangle Grid.Column="2" Fill="Red" />
    <GridSplitter Grid.Column="0" Width="5" HorizontalAlignment="Right" VerticalAlignment="Stretch" Background="Black" />
    <GridSplitter Grid.Column="2" Width="5" HorizontalAlignment="Left" VerticalAlignment="Stretch" Background="Black" />
  </Grid>

Click to go to a live demo.

The gridsplitters can also be put on opposite side of the center column for nearly the same effect. There are two differences when used this way. First, the space taken by the gridsplitters are inside the center column and secondly, the gridsplitters fully overlap when move moved all the way over.

   <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Rectangle Grid.Column="0" Fill="Green" />
    <Rectangle Grid.Column="1" Fill="White" />
    <Rectangle Grid.Column="2" Fill="Red" />
    <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Left" VerticalAlignment="Stretch" Background="Black" />
    <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Right" VerticalAlignment="Stretch" Background="Black" />
  </Grid>

Click to go to a live demo.

That is the basics of using gridsplitters. I’ll have some more advanced use of these controls in my next post.

May 28
Learning about Grid

I've been playing with XAML a little bit lately, both the Silverlight and WPF flavors, and thought I would discuss some of the things I learned about the <Grid /> control and a few of the concepts I had issues with.

The first concept I had to grasp was the fact that <Grid /> is a visual layout control. It has nothing to do with data. This reminds me of the good ol' days when I was allowed to use tables to layout my HTML pages. I actually had to convince myself this is a good thing. Microsoft designed it for layout so I should use it for layout.

When you start adding rows and columns to a test grid you will find that the first row or column is 0 not 1. From a layout standpoint the first row or column should be 1, but if you look from the development side the RowDefinitions and ColumnsDefinitions properties are collections where the first index is 0. Looks like designers will have to get used to 0 based indexing, but I'm a dev so it's fine by me.

There are three ways to size a row or column of a grid.

  1. Give a hard size. This can be data bound also, but it's basically giving a hard number.
  2. "Auto". The row or column takes on the size of its content.
  3. "N*" (Star sizing). The new wonder of the development world. Takes up the space not used by the auto or hard sizing and splits it between all of the star sized rows or columns.

Auto and hard sizing are easy concepts, but star sizing threw me for a loop for a bit. The way I understand star sizing comes down to being a number of units of remaining space. You just need to add up the number of stars to determine the number of units of remaining space.

For example, in the following grid the first row will take up a set size. Now for the remaining space there are 2 star rows so there are 2 units of remaining space. Therefore, the second and third rows will each take up half of the remaining space.

<Grid>

  <Grid.RowDefinitions>

    <RowDefinition Height="Auto"/>

    <RowDefinition Height="*"/>

    <RowDefinition Height="*"/>

  </Grid.RowDefinitions>

</Grid>

In this example there are 2 star rows but one uses 2 stars so there are 3 units of remaining space. So the first row takes up two thirds and second row gets one third of the remaining space.

<Grid>

  <Grid.RowDefinitions>

    <RowDefinition Height="2*"/>

    <RowDefinition Height="*"/>

  </Grid.RowDefinitions>

</Grid>

Another example I've seen is below. It makes it a little clearer to the reader that each of the rows is going to take up 50% of the remaining space.

<Grid>

  <Grid.RowDefinitions>

    <RowDefinition Height="50*"/>

    <RowDefinition Height="50*"/>

  </Grid.RowDefinitions>

</Grid>

Just remember star sizes use the remaining space so having a lot of auto or hard sized rows or columns can leave you with very little space to split up.

 

 

Here are a couple of notes and things I don't want to forget:

This will make a nice base which will resize itself whenever the user changes the window size:

<Grid>

<Grid.RowDefinitions>

<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*"/>

</Grid.ColumnDefinitions>

</Grid>

To put a control in row 0  and column 1 from XAML use the following:

<Rectangle Grid.Row="0" Grid.Column="1" />

To put a control in row 0 and column 1 from code use the following:

myControl.SetValue(Grid.RowProperty, 0);

myControl.SetValue(Grid.ColumnProperty, 1); 

myGrid.Children.Add(myControl)

October 31
The WebBrowser control with a custom User-Agent

We are using a WebBrowser control in a project I am working on and needed to use a custom User-Agent.  Searching the Internet only produced a way to change the User-Agent on a single request not for every request the WebBrowser control makes. 

It seems that the WebBrowser control only has one method to access headers, the WebBrowser.Navigate() method.  The code below intercepts all navigation request from the WebBrowser control and calls the WebBrowser.Navigate() method using a custom User-Agent.

 

public partial class Form1 : Form

{

    bool isUserAgentSet = false;

 

    public Form1()

    {

        InitializeComponent();

    }

 

    private void Form1_Load(object sender, EventArgs e)

    {

        this.webBrowser.Navigate(“Http://someurl.com”);

    }

 

    private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)

    {

        //Check if the custom user agent is set

        if (!isUserAgentSet)

        {

            //cancel the current request

            e.Cancel = true;

            this.isUserAgentSet = true;

 

            //Navigate to the desired location using the custom user agent

            this.webBrowser.Navigate(e.Url, e.TargetFrameName, null, "User-Agent: CustomUserAgent\r\n");

        }

    }

 

    private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)

    {

        //reset isUserAgentSet to prepare for the next navigate command

        this.isUserAgentSet = false;

    }

}

 

This code currently only works for GET requests.  I am working on a POST solution and will blog that code as soon as it is done.