1
votes

I have a seemingly simple use case but its been troubling me for hours

I have a grid with two rows and two columns, the first column should take all the available width and the second column should take the width it requires. The problem is with the 'required width' of the second column. This column contains a datagrid in the top row and a label (for simplicity) in the bottom row. The datagrid has two columns which should both take up 50% width of the datagrid.

I want:

  • If the label is wider than the datagrid the datagrid should scale up (and NO semi column MAY appear at the end of the datagrid filling up the remaining space)
  • If the datagrid is wider than the label, the column may not be smaller than the required size for the datagrid.

The problem:

  • If I set the datagrid columns to take all available space (width='*') it works if the label is bigger than the datagrid (but if the label is smaller the datagrid shrinks to the width of the label, and not al text is readable)
  • If I set the columns to 'autosize' it works is the label is smaller than the datagrid (but if the label is bigger the 'semi' column appears (and it really hurts my eyes)).

The code:

x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="400">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid Grid.Column="1" Name="grid">
        <!-- Change column width to simulate the problemn-->
        <DataGrid ItemsSource="{Binding Items}" ColumnWidth="*" RowHeaderWidth="0" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"/>
    </Grid>
    <!-- change label text to simulate problemn-->
    <Label Grid.Row="1" Grid.Column="1" Content="x"/>
</Grid>

  • The binding to the actual width of the grid is to have the columns scale up correctly
  • The Items is a List of objects (which contain two string values)
2

2 Answers

1
votes

This is dirty and would probably cause me to rethink my design, but it works based on your requirements. I'm not sure how else to achieve this without creating a custom control or greatly modifying the DataGrid default template, but here goes.

Change your DataGrid styling to this and give names to both the Label and the DataGrid.

<DataGrid Name="dg" ItemsSource="{Binding Items}" CanUserResizeColumns="False"/>
///
<Label Grid.Row="1" Grid.Column="1" Content="x" Name="label"/>

Then create a ContentRendered event for your MainWindow.

 Title="MainWindow" Height="450" Width="800" Name="mw" ContentRendered="Mw_ContentRendered">

Now in the render event, manually resize columns after the render occurs. You can't assign a star to the width as it won't resize correctly, so you need to divide your widths evenly base on column count.

private void Mw_ContentRendered(object sender, EventArgs e)
{    
     //Loop through columns and resize
     for (int x = 0; x < dg.Columns.Count; x++)
     {
         double div = dg.ActualWidth / dg.Columns.Count;
         double add = div - dg.Columns[x].ActualWidth;
         if (add < 0) { div += -add; }
         dg.Columns[x].Width = new DataGridLength(div);         
     }     
}

EDIT: Updated width logic to account for uneven widths

0
votes

I ended up creating my own user control.

This was relatively easy as I know at design time which rows I will have in the 'datagridview'.

Tronald's suggestion works, provided that the data does not change after rendering (mine does, both the datagrid contents and the 'label' change based on selections made in the rest of the application).

I still think that the 'Width="*" MinWidth="auto"' combination should be possible for a datagrid so If anybody has a solution.