I have a DataGrid in a Grid in a TabItem:
<TabItem Header="SomeHeader">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="TabHeight" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TabWidth"/>
</Grid.ColumnDefinitions>
<DataGrid Margin="10" Grid.Column="0" Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Stretch"
IsReadOnly="True"
AutoGenerateColumns="False">
</DataGrid>
</Grid>
</TabItem>
Problem is that DataGrid refuses to size to the containing Grid. What prevents it from doing so?
Your Grid shares its row and column sizes with the shared size groups TabWidth and TabHeight. Consequently, the sizes of the row and column that contain the DataGrid are determined among all Grids that share the same groups and are located in the same grid size scope like this:
Absolute values take precedence over Auto, so the largest explicit column size in the group wins, even if all others are defined as Auto
If all rows / columns are Auto-sized, the largest wins
Star-sizes (*) are treated as Auto (the default width of a column is 1*, so this rule applies then, too)
To clarify, the DataGrid is sized to fit its assigned row and column within the Grid, not the size of the Grid itself. If you want to size it to the containing tab, the Grid is redundant. Applying both a shared size to a row or a column and sizing it to fill its parent are opposing goals, choose one.
Related
I'm wanting to limit a Grid.ColumnDefinition to a maximum width but I do not know the width to do this programatically. Consider the following XAML:
<Grid MaxWidth="150" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="A" TextWrapping="Wrap" Background="LightGreen" />
<TextBlock Grid.Column="1" Text="B" TextWrapping="NoWrap" Background="LightSteelBlue" />
</Grid>
The Grid is 150px wide at most but can be less. The TextBlock in column 0 is Wrap. The TextBlock in column 1 is NoWrap. Background colors added simply for clarity. Result:
Now let's change the text:
<TextBlock Grid.Column="0" Text="I'm long but I wrap" TextWrapping="Wrap" Background="LightGreen" />
<TextBlock Grid.Column="1" Text="I'm a long single line" TextWrapping="NoWrap" Background="LightSteelBlue" />
Result:
The wrappable text does not wrap. Seems no feedback is provided from the Grid to the TextBlock. The behavior I want is for the Grid to realize that its columns being Auto have expanded past its own MaxWidth property and attempt to shrink the contents in the columns. The TextBlock that is NoWrap won't abide by this request while the TextBlock with Wrap would. Hence the output would be:
I can't figure out a way to do this with any * sizing since I don't want the grid to take this much space unless the contents are needed. Incidentally the actual Grid has many columns of many potential sizes. This is a shortened example.
[Edit]: My solution is a hack and I don't care for it, but it works. I created a property on my model which determines the content that can appear in other columns including images, margins, text, etc. Then it subtracts from the grid size to find a maximum width for a TextBlock which has Wrap set. Works just fine but is ugly as can be.
Although Auto does not work well for you, doing the * can work wonders. Instead of just a blind-eye to * for all other columns, you can do [a numeric value]*, like Width="120*" which will allocate the 120, but, if there is more room, it will get the rest.
Now, that said, if you have SOME columns that you know would be fixed, like some date field which is always 100 width, or some string type category of 1 character, maybe a fixed width of 10, but the rest are otherwise flexible. Just blend them something like
Width 100
Width 10
Width 500*
Width 250*
So, if your screen has available width of 1200, columns 1 and 2 will remain at their fixed widths. However, the 500* and 250* will get their baseline width and then equally split the remaining width between them. The more "*"-based columns to split the widths, they all split the available space.
Have you tried doing something like that?
I've got a grid with 3 columns: the first has its Width set to "*", which I have been led to believe will make it fill up any remaining space left by the other columns. The second has a width of 8, and the third's Width is set to "Auto" so its size changes depending on its contents.
In my 2nd column I have a GridSplitter, so that when dragged I can change the width of both the first and third columns. This works fine, the issue is that I have a grid in my third column that, when toggled, will have its visibility set to collapsed. When collapsed, I need the first column to fill all of the remaining space. I tried to do this many ways:
Set HorizontalAlignment on first column to Stretch
Bound the Grid.Rowspan of the first column to the visibility of the third one, so that when when hidden the Rowspan will change to 3 and, since its width is using "*", it should theoretically use all of the available space in all 3 columns.
The weird thing is that, if I do not resize the columns using the GridSplitter, then the first column will fill all remaining space properly. Yet after resizing, the first column will not budge. It's almost as if, when dragging the GridSplitter to resize the columns, WPF change the width of both columns to become absolute instead of their star and auto values, making it so they will not fill the space after a resize.
XAML Code (condensed) as requested:
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid x:Name="AssetListViewGrid" Grid.Column="0" Grid.RowSpan="{Binding Visibility, ElementName=AssetViewMetadataSplitter, Converter={StaticResource SplitterVisibilityToRowSpanConverter}}" Margin="0 4 0 4">
<!-- irrelevant code -->
</Grid>
<GridSplitter x:Name="AssetViewMetadataSplitter" Grid.Column="1" Opacity="0.8" HorizontalAlignment="Center" Width="6" Margin="3 5 1 5" ToolTip="Grab to resize" Visibility="{Binding IsChecked, ElementName=GridHeaderVisibilityToggleButton, Converter={StaticResource VisConverter}}"/>
<Grid x:Name="MetadataGrid" Margin="4 2 4 2" Grid.Column="2" DataContext="{Binding MetadataViewModel}" Visibility="{Binding IsChecked, ElementName=GridHeaderVisibilityToggleButton, Converter={StaticResource VisConverter}}">
<!-- irrelevant code -->
</Grid>
I just ran into this as well. In my app it seemed that a GridSplitter was in fact changing the width values to absolute instead of * also, so I'm guessing that is the behavior.
I ended up using code-behind to solve it. First, name column 1:
<ColumnDefinition Width="*" x:Name="Column1"/>
Then, add an event handler for when your MetadataGrid visibility changes, & call this code to reset Column1 to a * width to fill the rest:
Column1.Width = new GridLength(1, GridUnitType.Star);
You might also try doing something in the XAML with style triggers to reset the Column1 width to * based on the MetadataGrid's visibility state. My case was much more complex with custom sizes & varied conditions & expanders, so I used code-behind, so I'm not sure if xaml triggers would work for yoU or not . Hopefully that helps though.
I solved it by adding empty 10000X1000 rectangle inside it
<Grid Grid.Row="1" Grid.Column="1" Height="auto" HorizontalAlignment="Left" SizeChanged="Grid_SizeChanged">
<Image x:Name="currentImage" Height="auto" Width="auto" />
<Rectangle Width="10000" Height="10000" ></Rectangle>
<Canvas x:Name="currentImageOverLay"/>`</Grid>
I am trying to create a grid that consists several columns and rows. Inside of some columns and rows there are datagrids. Here is the question: How can i dynamically resize all grids in different columns and rows while I am enlarging the main window? I created all columns and rows like Height="x*" and Width="y*". In other words rows and columns are being resized while the main window is being resized but grids' size remains the same. I want to enlarge all grids and fill the whole column with the grid. I tried to fix grids' size with * and it did not work. Any idea how can i solve this problem ?
The default layout behaviour of WPF should give you what you expect.
For example, if you have only this in a Window:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Row="0" Grid.Column="0" />
</Grid>
The DataGrid should size with the window as you resize it, occupying exactly a quarter of the window in the top left corner.
Be careful that you aren't setting VerticalAlignment or HorizontalAlignment to something other than "Stretch".
If you mean to ask how to size the columns of the DataGrid dynamically, look at this question.
Edit: I try rephrasing my question, sorry if it was not clear. Thanks to all anyway.
Say I have a UserControl whose layout has a grid with 1 row x 3 columns, the first 2 autosized and the third star-sized:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox MinWidth="80" MaxWidth="150" .../>
<CheckBox Grid.Column="1" VerticalAlignment="Top".../>
<TextBox Grid.Column="2" MaxHeight="400" TextWrapping="Wrap" HorizontalAlignment="Stretch"...>
</Grid>
The TextBox has text wrapping and its vertical scrollbar visibility set to auto and its horizontal one hidden.
Now, I have some window including a ListBox whose items are instances of this UserControl, like:
<ListBox HorizontalContentAlignment="Stretch".../>
The ListBox is in a 1-column star-sized grid and thus stretches to fit all the available width in its container. When I resize the container of this ListBox the ListBox too resizes as expected as it is stretched in a star-sized Grid column; and the same holds true for the ListBox items', which too are stretched and in this case happen to be instances of a UserControl with the above layout (3 columns in a grid, the 3rd star-sized).
The problem is that the TextBox in the 3rd column of the UserControl used as a listbox item should not automatically increase its width when I type into it some long text: it should just wrap, increasing its height (up to a maximum height; then the vertical scrollbar will appear). In other words, its MaxWidth should be determined by the available space, like its Width.
How should I code my XAML for this?
That should be the behavior by default, based on the code you've posted.
Try setting your TextBox's HorizontalAlignment="Stretch"
Ok I have a contentpresenter inside a grid cell:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<WrapPanel Grid.Row="0" Grid.Column="0">
<RadioButton GroupName="a" IsChecked="{Binding Path=SpecifyRatedValues, Mode=TwoWay}">Specify</RadioButton>
<RadioButton GroupName="b" IsChecked="{Binding Path=SpecifyRatedValues, Converter={StaticResource invertBoolean}}">Auto generate</RadioButton>
</WrapPanel>
<Border BorderBrush="Black" BorderThickness="3" Grid.Row="1" Grid.Column="0">
<ContentPresenter Content="{Binding Path=RatedValues}"></ContentPresenter>
</Border>
</Grid>
The contentpresenter finds which UI element to use by the datatemplate defined under resources:
<DataTemplate DataType="{x:Type ViewModels:RatedValuesViewModel}">
<Views:RatedValuesView />
</DataTemplate>
Now, everything works as expected, except for one thing: the View which is placed inside the contentpresenter at runtime does not expand to fill the entire cell. It leaves a big margin on the left and right side.
How can I make the view inside the contentpresenter fill the entire available area?
HorizontalAlign="Stretch" and VerticalAlign="Stretch" are important; however, you also have to remember how Grids work. Grid units are either in absolute pixels, "Auto", which means they size to fit their contents (i.e. minimum size to show everything), or "stars" which means fill up all available space.
Set your second RowDefinition's height to "*". You may also want to set easily-distinguishable border brushes and thicknesses on your grid. Sometimes, it's easy to think X isn't filling up all the available space, when it's really X's container, or X's container's container that isn't filling up the space. Use bright primary colors and large thicknesses (3 or so) and you can tell quickly who's not filling things up.
Chaiguy got it! The View had an explict Width and Height which constrained the view when placed in the cell. Thanks :-)
You must set HorizontalAlign=Stretch, VerticalAlign=Stretch to both Border and Content Presenter to fill the space in grid. and make width=auto.