Reputation: 193
I use Visual Studio 2010. I've been struggling trying to get a datagrid to fill the existing space. If necessary, to show a scrollbar on the datagrid, not on the page.
Example code:
<Page x:Class="TestApp.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<StackPanel>
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</StackPanel>
</Viewbox>
</Expander>
</Grid>
The problem is, it seems, whatever I do, the datagrid will always stretch until all columns are completely visible, even if it stretches way past the window (or page) size. Note: I have a panel on the right, showing status, dates, info, ..., which should stay on the screen.
I have tried too many things to list them all. The only working 'solution' I found is adding another control (invisible) like a separator on the grid and binding the expander width to the width of the separator. It works, but it's crappy programming.
MaxWidth="{Binding ElementName=MySeparator, Path=ActualWidth}"
Binding the width of the stackpanel to the (actual) width of the column just make the stackpanel disappear.
Can someone please help me. Thank you.
-- Update -- This is what I like to achieve:
It seems that if I use hardcoded column widths, this problem doesn't occur. Only if there is a column that has a star-length, the datagrid takes as much space as it needs.
Upvotes: 2
Views: 4044
Reputation: 193
Thanks everyone for the efforts. The solution was proposed by Mike Strobel in a comment. Since I can't mark comments as, I'll repeat it here.
I had a window, containing a scrollviewer, where all page are placed on. I removed the scrollviewer from the window and placed the scrollbars on the page.
<Page x:Class=...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<Grid>
This actually solves the problem! Thanks Mike!
(If you run into this problem as well, please give mike's comment a thumbs up as well).
Upvotes: 1
Reputation: 25623
Since your diagram only addressed the scrolling issue, I have focused on that for now. It's still not entirely clear to me how you want this layout to look before scrolling is required, but let's use this as a starting point. Give it a try, and if the behavior isn't what you had in mind, please try to be as specific as possible about what needs to change (a picture is worth a thousand words).
For brevity, I'm only including the Expander
and its content. The ancestor elements are exactly as they were in your original post.
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<StackPanel>
<DataGrid Margin="5"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<!-- Temporary items source to demonstrate grid measuring to fit rows -->
<DataGrid.ItemsSource>
<x:Array Type="s:String">
<s:String>Dummy Row 1</s:String>
<s:String>Dummy Row 2</s:String>
<s:String>Dummy Row 3</s:String>
</x:Array>
</DataGrid.ItemsSource>
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn" />
<DataGridTextColumn Header="MySecondColumn" />
<DataGridTextColumn Header="MyThirdColumn" />
<DataGridTextColumn Header="MyFourthColumn" />
<DataGridTextColumn Header="MyFifthColumn" />
<DataGridTextColumn Header="MySixthColumn" />
<DataGridTextColumn Header="MySeventhColumn" />
<DataGridTextColumn Header="MyEighthColumn" />
<DataGridTextColumn Header="MyNinthColumn" />
<DataGridTextColumn Header="MyTenthColumn" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click" />
</StackPanel>
</Expander>
This is how it looks with two columns:
[
This is how it looks with ten columns:
According to your comments on another answer, your page is loaded inside a ScrollViewer
at runtime. If that ScrollViewer
supports horizontal scrolling, then that is the root of you problems: it will give your page as much horizontal space as it needs, and that need is being driven by the DataGrid
. One (hacky) workaround would be to wrap your DataGrid
in a custom decorator that fakes its desired width when measured and then fills whatever horizontal space is available when arranged. If you want to try this out, use my example from above, but wrap the DataGrid
in a decorator like so:
<l:ZeroWidthDecorator xmlns:l="clr-namespace:TestApp">
<DataGrid><!-- ... --></DataGrid>
</l:ZeroWidthDecorator>
The code for the decorator is as follows:
public class ZeroWidthDecorator : Border
{
private Size _lastSize;
private Size _idealSize;
protected override void OnVisualChildrenChanged(DependencyObject added, DependencyObject removed)
{
base.OnVisualChildrenChanged(added, removed);
_idealSize = new Size();
_lastSize = new Size();
}
protected override Size MeasureOverride(Size constraint)
{
var child = this.Child;
if (child == null)
return new Size();
if (child.IsMeasureValid)
child.Measure(new Size(_lastSize.Width, Math.Max(_lastSize.Height, constraint.Height)));
else
child.Measure(new Size(0d, constraint.Height));
_idealSize = child.DesiredSize;
return new Size(0d, _idealSize.Height);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
var child = this.Child;
if (child != null)
{
if (arrangeSize != _lastSize)
{
// Our parent will assume our measure is the same if the last
// arrange bounds are still available, so force a reevaluation.
this.InvalidateMeasure();
}
child.Arrange(new Rect(arrangeSize));
}
_lastSize = arrangeSize;
return arrangeSize;
}
}
I haven't tested this extensively, but I tried a few different scenarios, and it seems to work. Use it at your own risk.
Upvotes: 1
Reputation: 169200
Get rid of the StackPanel
:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</Viewbox>
</Expander>
</Grid>
StackPanels
and ScrollViewers
don't work well together because of the way a StackPanel
measures its children:
XAML/WPF - ScrollViewer which has StackPanel inside is not scrolling
And since the default control template of the DataGrid
includes a ScrollViewer
you don't need to add your own one.
Upvotes: 0
Reputation: 975
Try wrapping your DataGrid
with ScrollViewer
like this:
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid>
// SOME CONTENT
</DataGrid>
</ScrollViewer>
Also I don't know if you need that ViewBox
at all. Try removing it and see if it fits your needs.
Upvotes: 0