Bra*_*ore 7 wpf layout datagrid
基本上,我想让WPF DataGrid控件布局完全按照WinForms DataGridView的方式进行.
更具体地说,这是我正在寻找的行为:
网格控件应该占用它给定的空间(即,在其父控件中有足够的空间可供它使用).这里我指的是控件,而不是列.
创建的列(无论是自动还是手动)可能占用也可能不占用所有这些空间.
如果在创建列后剩余额外空间,则不应展开最后一列以填充此空间
如果在创建列之后剩余额外空间,则不应创建其中没有任何内容的空列来填充此额外空间
据我所知,在WPF中,最后两个要点似乎是互斥的,你必须选择其中一个.有没有人找到办法做到这两点?我搜索了很多,并没有找到我正在寻找的东西,但是我发现的所有帖子往往都是几年了所以我希望有人已经把这个问题弄清楚了.
编辑:sa_ddam213,这是一个快速的xaml项目,我把它放在一起测试你的建议.
<Window x:Class="DataGridFix.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridFix"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="data"
ObjectType="{x:Type local:TestObject}"
MethodName="GetTestData" />
</Window.Resources>
<StackPanel>
<DataGrid HorizontalAlignment="Left" ColumnWidth="Auto" Height="150" VerticalAlignment="Top" ItemsSource="{Binding Source={StaticResource data}}" />
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
这是背后的代码:
namespace DataGridFix {public class TestObject {public int Id {get; 组; public string Name {get; 组; }
public static List<TestObject> GetTestData()
{
var items = new List<TestObject>();
items.Add(new TestObject() { Id = 1, Name = "Joe" });
items.Add(new TestObject() { Id = 2, Name = "Matt" });
items.Add(new TestObject() { Id = 3, Name = "Hal" });
return items;
}
}
Run Code Online (Sandbox Code Playgroud)
}
我从你的建议中看到的唯一值得注意的事情是将HorizontalAlignment设置为Left.我这样做了,并尝试将ColumnWidth设置为各种设置,但每个设置都有相同的问题(当然除了*......从技术上来说,我可以搞砸那个但我不会进入那个).
如果使用鼠标展开任何列,然后减小列大小,则会显示空填充列.我在你的帖子中注意到的另一个不同之处是你将DataGrids放在StackPanel中,因为你有多个.我试过它只是为了它,但同样的结果.如果您发现我正在做什么和您建议的内容之间有任何其他区别,请告诉我.
为了获得您想要的行为,您可能需要修改控件模板DataGrid.
看看代码.我DataGridView认为我已经非常接近WinForms的外观了.
要删除额外的色谱柱,您必须从中删除填料色谱柱DataGridColumnHeadersPresenter.我刚刚评论过它.其余的只是默认模板.
另一修改是的模板DataGrid.
通过设置HorizontalAlignment="Left"上ScrollContentPresenter,该行不再占用控制的所有宽度.
这些是我对默认模板进行的唯一2次更改.

<Style TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid>
<!-- Remove this filler column -->
<!--<DataGridColumnHeader x:Name="PART_FillerColumnHeader" IsHitTestVisible="False" />-->
<ItemsPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ScrollViewer Focusable="false" Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
Style="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type DataGrid}, ResourceId=DataGridSelectAllButtonStyle}}"
Focusable="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}" />
<DataGridColumnHeadersPresenter Grid.Column="1" Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
<!-- Set HorizontalAlignment="Left" to have the rows only take up the width they need and not fill the entire width of the DataGrid -->
<ScrollContentPresenter HorizontalAlignment="Left" x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar Grid.Row="1" Grid.Column="2" Name="PART_VerticalScrollBar"
Orientation="Vertical"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar Grid.Column="1"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
更新
确实看起来.NET 4和.NET 4.5之间存在差异.
我在使用Visual Studio 2012的Windows 8计算机上进行开发,因此作为测试,我尝试使用.NET 4来查看是否可以复制错误的行为.但它仍然工作正常.
可以肯定的是,我尝试在安装了.NET 4的另一台机器上运行应用程序,这里空行显示为更大的列然后再缩小.
问题似乎DataGridRows是行为不正常.在仅安装了.NET 4的计算机上运行时,它们会在使列更小时保持其当前大小.在.NET 4.5上,他们按预期调整大小.
获得所需行为的新解决方案实际上比前一个简单得多.
通过简单的设置HorizontalAlignment就DataGridRows到left,并去除填充柱,它的工作原理上都.NET 4和.NET 4.5.并且不再需要替换整个模板DataGrid.
<Style TargetType="DataGridRow">
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style TargetType="DataGridColumnHeadersPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid>
<ItemsPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
WPF中的列有很多布局选项,只需选择要显示的内容即可.
如果你设定的HorizontalAlignment到Left的DataGrid将调整基础上,以适应其内容的ColumnWidth你挑选.
以下是一些可用列设置的示例
<StackPanel>
<DataGrid HorizontalAlignment="Left" ColumnWidth="100" Height="64" VerticalAlignment="Top" ItemsSource="{Binding ElementName=UI, Path=GridItems}" />
<DataGrid HorizontalAlignment="Left" ColumnWidth="SizeToCells" Height="64" VerticalAlignment="Top" ItemsSource="{Binding ElementName=UI, Path=GridItems}" />
<DataGrid HorizontalAlignment="Left" ColumnWidth="SizeToHeader" Height="64" VerticalAlignment="Top" ItemsSource="{Binding ElementName=UI, Path=GridItems}" />
<DataGrid HorizontalAlignment="Left" ColumnWidth="Auto" Height="64" VerticalAlignment="Top" ItemsSource="{Binding ElementName=UI, Path=GridItems}" />
<DataGrid HorizontalAlignment="Left" ColumnWidth="*" Height="64" VerticalAlignment="Top" ItemsSource="{Binding ElementName=UI, Path=GridItems}" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
