Confessions of a .NET Developer!

Auto-fixing height and width of Button in WPF DataGrid

This short post will explain how to automatically fix the height and width of a Button in WPF DataGrid.
The idea is to take the height and width of the cell containing the button. To set a proper margin, we can reduce both the parameters by using a converter.
First the DataGrid:

        <DataGrid VerticalContentAlignment="Center"
                  RowHeight="50" ColumnWidth="*"                  
                  ItemsSource="{Binding Path=Persons}" 
                  IsReadOnly="True"
                  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}"/>
                <DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}"/>
                <DataGridTextColumn Header="Address" Binding="{Binding Path=Address}"/>
                <DataGridTemplateColumn Header="Select">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Select"
                                    Height="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Path=ActualHeight}"
                                    Width="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Path=ActualWidth}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

Lets take a close look at the “Select” column. Its a DataGridTemplateColumn with each row having a Select button. The Button’s height and width is provided by its visual container DatGridCell using the RelativeSource Binding.
It will look something like this:
With no converter

But it doesn’t look good, what’s required is to provide margin. Simply giving margin won’t help.
A converter will be required here to reduce the height and width of the button. On further research, I figured out that a combination of converter and margin can solve the issue, but its still quite unclear to me how it works.

Here is the converter that is used:

    class HeightWidthFixerConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (parameter != null && value != null)
            {
                double reduceBy;
                if (double.TryParse(parameter.ToString(), out reduceBy))
                    return (double)value - reduceBy;
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

The ConverterParameter will be used to specify how much height or width you want to reduce by.
The CellTemplate for the DataGrid will look something like this:
Here is the resource key for converter:

    <Window.Resources>
        <converter:HeightWidthFixerConverter x:Key="heightWidthFixer"/>
    </Window.Resources>

And the CellTemplate:

                <DataGridTemplateColumn Header="Select">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Select"
                                    Margin="2"
                                    Height="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Path=ActualHeight, Converter={StaticResource heightWidthFixer}, ConverterParameter=10}"
                                    Width="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Path=ActualWidth, Converter={StaticResource heightWidthFixer}, ConverterParameter=7}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

The height and width has been reduced by 10 & 7 respectively.
The DataGrid will look like something like this:

With Converter

With Converter

It looks fine now, properly spaced. Surely this hack is not the finest, so I would like to hear your thoughts and suggestions for improvement. Somehow I feel there must be some better way to do this, until then I shall use this. Thank you for reading and have a nice day!

Advertisements

December 20, 2011 - Posted by | WPF

4 Comments »

  1. Grid? Create a 3×3 grid with fixed border columns and rows, and place the button in the middle cell. But I don’t know if it’s faster than using a converter.

    Comment by Mike | June 26, 2012 | Reply

  2. super

    Comment by renjith K | September 11, 2013 | Reply

  3. how to replace the ConverterParameter=7 to something like ConverterParameter={Binding MyProperty}?

    thanks!

    Comment by Manuel | February 27, 2014 | Reply

  4. Hi Manuel,

    You can’t have a binding in ConverterParameter, as this is not a DependencyProperty. if this is a one-time show, you can use a {StaticResource …}. If you need a runtime behaviour, you need to write a custom MultiValueConverter.

    Comment by Mike | March 19, 2014 | Reply


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: