如何使 WPF 数据网格中的最后一列始终占据所有左侧空间?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4389630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make the last column in WPF datagrid take all the left space, always?
提问by greenoldman
Standard WPF 4 Datagrid.
标准 WPF 4 数据网格。
Let' say I have datagrid 200 pixels wide, and 2 columns. I would like the columns take always entire space, meaning if the user resizes the first column to 50 pixels, the last one would be 150.
假设我有 200 像素宽和 2 列的数据网格。我希望列始终占据整个空间,这意味着如果用户将第一列的大小调整为 50 像素,则最后一列将是 150。
Initially I set width 100 pixels for the 1st column, and * for the last one (in XAML).
最初我将第一列的宽度设置为 100 像素,最后一列(在 XAML 中)设置为 *。
I thought the problem is with removing the virtual, 3rd column, as explained here:
我认为问题在于删除虚拟的第 3 列,如下所述:
http://wpf.codeplex.com/Thread/View.aspx?ThreadId=58939
http://wpf.codeplex.com/Thread/View.aspx?ThreadId=58939
but there is no difference really -- still, when resizing the columns, I get some extra space on right -- with virtual column, it is a virtual column (white color by default), without it, it is empty space (gray by default).
但实际上并没有什么区别 - 尽管如此,在调整列大小时,我会在右侧获得一些额外的空间 - 使用虚拟列,它是一个虚拟列(默认为白色),没有它,它是空白空间(灰色默认)。
QUESTION: how to enforce the constraint, that no matter how the user resizes the columns,
问题:如何强制约束,无论用户如何调整列的大小,
sum(columns width)==datagrid width
?
?
Edits
编辑
Yes, I use WPF 4.
是的,我使用 WPF 4。
WORKAROUND
变通方法
I marked one of the answers as solution, but actually it is not a solution due to WPF design. It is simply what WPF can do at best, and it is not very good -- first of all the option CanUserResize for column means really IsResizeable and this option when turned on contradicts Width set to *. So without some really smart trick you end up with:
我将其中一个答案标记为解决方案,但实际上由于 WPF 设计,它不是解决方案。这只是 WPF 最多可以做的,而且不是很好——首先,列的 CanUserResize 选项意味着真正的 IsResizeable,并且这个选项在打开时与设置为 * 的 Width 相矛盾。所以如果没有一些真正聪明的技巧,你最终会得到:
datagrid which last column in superficially resizable but in fact it is not, and little space on right is shown (i.e. the virtual column is not resizable) -- for last column: CanUserResize=true, Width=*
datagrid which last column cannot be resized by user and it is shown accordingly, initially no space on right is shown, but it can be shown when user resizes any element of datagrid -- for last column: CanUserResize=false, Width=*
datagrid 最后一列在表面上可调整大小,但实际上不是,右侧显示的空间很小(即虚拟列不可调整大小)——对于最后一列:CanUserResize=true, Width=*
最后一列不能被用户调整大小的数据网格,它会相应地显示出来,最初没有显示右侧的空间,但是当用户调整数据网格的任何元素的大小时可以显示它——对于最后一列:CanUserResize=false, Width=*
So far I can see two problems with WPF datagrid:
到目前为止,我可以看到 WPF 数据网格的两个问题:
- misleading naming
- contradiction of features
- 误导性命名
- 特征的矛盾
I am still all ears to how really solve this issue.
我仍然完全了解如何真正解决这个问题。
采纳答案by Babak Naffas
Set the width for the data grid to "Auto". You're allowing the columns to resize correctly within the grid itself, but you've hard-wired the width to 200.
将数据网格的宽度设置为“自动”。您允许列在网格本身内正确调整大小,但您已将宽度硬连线为 200。
UPDATE: Base on @micas's comment, I may have misread. If that's the case, try using 100 for the left column's width and 100* for the right column (note the asterisk). This will default the width for the right column to 100 but allow it to resize to fill the grid.
更新:根据@micas 的评论,我可能误读了。如果是这种情况,请尝试对左列的宽度使用 100,对右列使用 100*(注意星号)。这会将右列的宽度默认为 100,但允许它调整大小以填充网格。
回答by biju
You can set a column width to star on code. In your constructor, add:
您可以设置列宽以在代码上加星标。在您的构造函数中,添加:
Loaded += (s, e) => dataGrid1.Columns[3].Width =
new DataGridLength(1, DataGridLengthUnitType.Star);
回答by Dr. ABT
I've just implemented this as an attached behavior. The problem is when you set the DataGrid's last column to *, it does resize to fit, but then all the auto-fitting of the other cells messes up. To resolve this, the attached behaviour does a manual auto-fit of other (non last) cells.
我刚刚将其实现为附加行为。问题是当您将 DataGrid 的最后一列设置为 * 时,它确实会调整大小以适应,但随后其他单元格的所有自动拟合都搞砸了。为了解决这个问题,附加的行为会手动自动适应其他(非最后)单元格。
This also works when resizing the other columns - once loaded, you can resize and the last column will always fill. Note this behavior works once on the Loaded event
这也适用于调整其他列的大小 - 加载后,您可以调整大小并且最后一列将始终填充。请注意,此行为在 Loaded 事件上起作用一次
// Behavior usage: <DataGrid DataGridExtensions.LastColumnFill="True"/>
public class DataGridExtensions
{
public static readonly DependencyProperty LastColumnFillProperty = DependencyProperty.RegisterAttached("LastColumnFill", typeof(bool), typeof(DataGridExtensions), new PropertyMetadata(default(bool), OnLastColumnFillChanged));
public static void SetLastColumnFill(DataGrid element, bool value)
{
element.SetValue(LastColumnFillProperty, value);
}
public static bool GetLastColumnFill(DataGrid element)
{
return (bool)element.GetValue(LastColumnFillProperty);
}
private static void OnLastColumnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dataGrid = d as DataGrid;
if (dataGrid == null) return;
dataGrid.Loaded -= OnDataGridLoaded;
dataGrid.Loaded += OnDataGridLoaded;
}
private static void OnDataGridLoaded(object sender, RoutedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null) return;
var lastColumn = dataGrid.Columns.LastOrDefault();
if(lastColumn != null)
lastColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
// Autofit all other columns
foreach (var column in dataGrid.Columns)
{
if (column == lastColumn) break;
double beforeWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToCells);
double sizeCellsWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToHeader);
double sizeHeaderWidth = column.ActualWidth;
column.MinWidth = Math.Max(beforeWidth, Math.Max(sizeCellsWidth, sizeHeaderWidth));
}
}
}
回答by pennyrave
Be forewarned: It's a hack....
预先警告:这是一个黑客......
I registered to the "AutoGeneratedColumns" event in the "OnLastColumnFillChanged" method of Dr. ABT's class and copied the Loaded method into it, and it works. I haven't really thoroughly tested it yet, so YMMV.
我在Dr. ABT的类的“OnLastColumnFillChanged”方法中注册了“AutoGeneratedColumns”事件,并将 Loaded 方法复制到其中,它可以工作。我还没有真正彻底地测试过它,所以 YMMV。
My change:
我的改变:
private static void OnLastColumnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dataGrid = d as DataGrid;
if (dataGrid == null) return;
dataGrid.Loaded -= OnDataGridLoaded;
dataGrid.Loaded += OnDataGridLoaded;
dataGrid.AutoGeneratedColumns -= OnDataGrid_AutoGeneratedColumns;
dataGrid.AutoGeneratedColumns += OnDataGrid_AutoGeneratedColumns;
}
private static void OnDataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null) return;
var lastColumn = dataGrid.Columns.LastOrDefault();
if (lastColumn != null)
lastColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
// Autofit all other columns
foreach (var column in dataGrid.Columns)
{
if (column == lastColumn) break;
double beforeWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToCells);
double sizeCellsWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.SizeToHeader);
double sizeHeaderWidth = column.ActualWidth;
column.MinWidth = Math.Max(beforeWidth, Math.Max(sizeCellsWidth, sizeHeaderWidth));
}
}
Oh, and don't forget to add the namespace to the XAML declaration! :)
哦,不要忘记将命名空间添加到 XAML 声明中!:)
Up top:
顶部:
xmlns:ext="clr-namespace:TestProject.Extensions"
And then in the DataGrid declaration:
然后在 DataGrid 声明中:
ext:DataGridExtensions.LastColumnFill="True"
Update: I said that the mileage would vary! Mine certainly did.
更新:我说里程会有所不同!我的当然有。
That whole "autofit columns" bit caused some of my columns in a DataGrid with a variable number of columns to only be as wide as the column header. I removed that portion, and now it seems to be working on all of the DataGrids in the application.
整个“自动调整列”位导致我在 DataGrid 中具有可变列数的某些列仅与列标题一样宽。我删除了那部分,现在它似乎可以处理应用程序中的所有 DataGrid。
Now I have:
我现在有:
private static void OnDataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null) return;
UpdateColumnWidths(dataGrid);
}
private static void OnDataGridLoaded(object sender, RoutedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null) return;
UpdateColumnWidths(dataGrid);
}
private static void UpdateColumnWidths(DataGrid dataGrid)
{
var lastColumn = dataGrid.Columns.LastOrDefault();
if (lastColumn == null) return;
lastColumn.Width = new DataGridLength(1.0d, DataGridLengthUnitType.Star);
}
回答by Jay
Here's a very simple answer, all performed in code behind. :-) All columns will be auto-sized; the final column will fill all remaining space.
这是一个非常简单的答案,全部在后面的代码中执行。:-) 所有列都将自动调整大小;最后一列将填充所有剩余空间。
// build your datasource, e.g. perhaps you have a:
List<Person> people = ...
// create your grid and set the datasource
var dataGrid = new DataGrid();
dataGrid.ItemsSource = people;
// set AutoGenerateColumns to false and manually define your columns
// this is the price for using my solution :-)
dataGrid.AutoGenerateColumns = false;
// example of creating the columns manually.
// there are obviously more clever ways to do this
var col0 = new DataGridTextColumn();
col0.Binding = new Binding("LastName");
var col1 = new DataGridTextColumn();
col1.Binding = new Binding("FirstName");
var col2 = new DataGridTextColumn();
col2.Binding = new Binding("MiddleName");
dataGrid.Columns.Add(col0);
dataGrid.Columns.Add(col1);
dataGrid.Columns.Add(col2);
// Set the width to * for the last column
col2.Width = new DataGridLength(1, DataGridLengthUnitType.Star);