Tony Vitabile
Tony Vitabile

Reputation: 8594

DataGrid Columns not autosizing properly

I have a DataGrid control in my application:

<DataGrid AutoGenerateColumns="False"
          BorderThickness="1"
          CanUserDeleteRows="False"
          CanUserReorderColumns="False"
          CanUserResizeColumns="True"
          CanUserResizeRows="False"
          CanUserSortColumns="True"
          EnableColumnVirtualization="True"
          EnableRowVirtualization="True"
          FontSize="16"
          FontWeight="Bold"
          IsReadOnly="True"
          Grid.Column="0"
          Grid.ColumnSpan="2"
          Grid.Row="2"
          Margin="5"
          Name="PendingRowsGrid"
          SelectionUnit="FullRow"
          ScrollViewer.CanContentScroll="True"
          ScrollViewer.HorizontalScrollBarVisibility="Auto"
          ScrollViewer.VerticalScrollBarVisibility="Auto"
          ToolTip="Number of rows pending transmission"
          Visibility="{Binding Converter={StaticResource BoolToHide}, Path=AdvancedSettings.RunningStandAlone, RelativeSource={RelativeSource AncestorType={x:Type cs:Dashboard}}}">
    <DataGrid.Columns>
        <cs:ExtendedTextColumn Binding="{Binding Mode=OneWay, Path=Value.DataTypeDisplay}"
                               Header="Data Type"
                               Width="*" />
        <cs:ExtendedTextColumn Binding="{Binding Converter={StaticResource CountConverter}, ConverterParameter='#,##0', Mode=OneWay, Path=Value.ToEoc}"
                               Header="To EOC"
                               HorizontalAlignment="Right"
                               Width="Auto" />
        <cs:ExtendedTextColumn Binding="{Binding Converter={StaticResource CountConverter}, ConverterParameter='#,##0', Mode=OneWay, Path=Value.FromEoc}"
                               Header="From EOC"
                               HorizontalAlignment="Right"
                               Width="Auto" />
    </DataGrid.Columns
</DataGrid>

The first column is left aligned, and the last two columns need to be right aligned. In addition, the right most 2 columns need to adjust their widths to fit the widest value in the column.

Here's the code for the ExtendedTextColumn class:

public class ExtendedTextColumn : DataGridTextColumn {

    public static readonly DependencyProperty HorizontalAlignmentProperty =
        DependencyProperty.Register( "HorizontalAlignment", typeof( HorizontalAlignment ), typeof( ExtendedTextColumn ),
                                     new PropertyMetadata( HorizontalAlignment.Stretch ) );

    public static readonly DependencyProperty VerticalAlignmentProperty =
        DependencyProperty.Register( "VerticalAlignment", typeof( VerticalAlignment ), typeof( ExtendedTextColumn ),
                                     new PropertyMetadata( VerticalAlignment.Stretch ) );

    public HorizontalAlignment HorizontalAlignment {
        get { return (HorizontalAlignment) GetValue( HorizontalAlignmentProperty ); }
        set { SetValue( HorizontalAlignmentProperty, value ); }
    }

    public VerticalAlignment VerticalAlignment {
        get { return (VerticalAlignment) GetValue( VerticalAlignmentProperty ); }
        set { SetValue( VerticalAlignmentProperty, value ); }
    }

    protected override FrameworkElement GenerateElement( DataGridCell cell, object dataItem ) {
        FrameworkElement element = base.GenerateElement( cell, dataItem );

        // Set the FrameworkElement's HorizontalAlignment and VeritcalAligment properties
        element.HorizontalAlignment = HorizontalAlignment;
        element.VerticalAlignment   = VerticalAlignment;
        return element;
    }

    protected override FrameworkElement GenerateEditingElement( DataGridCell cell, object dataItem ) {
        TextBox textBox = (TextBox) base.GenerateEditingElement( cell, dataItem );

        // Set the TextBox's TextAlignment and VeritcalAligment properties
        textBox.TextAlignment            = GetTextAlignment();
        textBox.VerticalContentAlignment = VerticalAlignment;
        return textBox;
    }

    private TextAlignment GetTextAlignment() {
        switch ( HorizontalAlignment ) {
            case HorizontalAlignment.Center:
                return TextAlignment.Center;

            case HorizontalAlignment.Left:
                return TextAlignment.Left;

            case HorizontalAlignment.Right:
                return TextAlignment.Right;

            default:
                return TextAlignment.Justify;
        }
    }
}

}

The problem is that the two right most columns are not sized properly with the XAML shown. I've also tried using DataGridTemplateColumns for the right-most two columns:

        <DataGridTemplateColumn Header="To EOC"
                                HeaderStyle="{StaticResource CenteredHeaderText}"
                                Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock TextAlignment="Right" 
                               Text="{Binding Converter={StaticResource CountConverter}, ConverterParameter='#,##0', Mode=OneWay, Path=Value.ToEoc}" 
                               VerticalAlignment="Center" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="From EOC"
                                HeaderStyle="{StaticResource CenteredHeaderText}"
                                Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock TextAlignment="Right" 
                               Text="{Binding Converter={StaticResource CountConverter}, ConverterParameter='#,##0', Mode=OneWay, Path=Value.FromEoc}" 
                               VerticalAlignment="Center" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

But these, also, do not size properly. In both cases, one to one and a half characters get cut off. In the case of the original XAML (using the ExtendedTextColumn class), it's the left most character that gets cut off; in the second XAML (the DataGridTemplateColumn case), it's the right most character.

I've tried changing the original XAML so the DataGrid uses DataGridTextColumns for the right-most two columns and these do get sized properly. This leads me to believe that there's something the DataGrid or DataGridTextColumn class does that isn't being done in the other two cases to determine how wide the column is, yet my ExtendedTextColumn class descends from DataGridTextColumn. I'm at a loss.

Does anyone have any suggestions for how I can get this to work properly?

Upvotes: 1

Views: 1080

Answers (1)

Tony Vitabile
Tony Vitabile

Reputation: 8594

After playing with the Xaml & the code for most of the day, I've come up with something that almost works.

First, I stopped using my class and I used XAML similar to the following for the right two columns instead:

<DataGridTextColumn Binding="{Binding Value.FromEoc, ConverterParameter=#\,##0, Converter={StaticResource CountConverter}, Mode=OneWay}"
                    Header="From EOC"
                    HeaderStyle="{StaticResource CenteredHeaderText}"
                    MinWidth="80"
                    Width="*">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Right" />
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

I figured that since the DataGridTextColumn resized properly by itself that this would do the trick. Alas, it did not. The Column ended up being 1/2 character too narrow!

So in the end, I punted. The original problem was that the columns were too narrow if the number of digits to be displayed was 8 or greater. I changed the Width of the first column to Auto and the Widths of the last two columns to *. The columns are now wide enough that I shouldn't have a problem until the number of digits is greater than 12 or so, and we shouldn't have that many digits in a production system.

Upvotes: 1

Related Questions