【发布时间】:2011-01-02 10:07:20
【问题描述】:
目标
我想为 DataGrid(标准,来自 WPF)设置这样的大小,以便所有单元格(文本)都完全可见。我有一个带有 DockPanel 的窗口,里面有 DataGrid,所以当我调整窗口大小时,所有嵌套的小部件(DockPanel 和 DataGrid)都会相应地调整大小。
示例(edit-1)
假设您有一个 100 像素宽的窗口,并且您有一个包含一列的 DataGrid,其中的单元格是“快速棕色狐狸...”(400 像素宽)。因此,DataGrid 应调整为 400 像素(可能更多,因为填充),Window 也应该调整为 400 像素(也更多,因为填充)。
我没有找到任何标准方法来做到这一点(AFAIK WPF 提供了将内容剪辑到所需宽度的方法,我的问题正好相反),所以我想出了这种丑陋的解决方法,但效果不太好。
解决方法
- 遍历 DataGrid 标题(假设它们只是字符串)并计算文本所需的宽度
- 遍历每列的 DataGrid 行(假设它们是 TextBlock 或 TextBox)并计算文本所需的最大宽度 -- 为 TextBlock/TextBox 添加水平填充和为 DataGrid 单元格添加水平边距
- 汇总列的 DataGrid ActualWidth 与 (2) 中计算的最大宽度之间的所有差异
- 按照 (3) 中计算的差值增加窗口宽度
问题
我做了几个测试,在某些情况下计算的宽度太大(这是小问题),在某些情况下太小了。问题从它的核心过程开始——计算 TextBox/TextBlock 所需的宽度,计算的宽度总是比它应该的小 1 个单位(如果我将宽度设置为计算的 1,文本中的 1 个像素总是被剪裁)。
那么我在这里忽略了哪个因素?或者更好 -- 是否已经有一些方法可以调整 DataGrid 的大小以适应其内容?
代码
计算文本所需的宽度(此处为 TextBlock):
public static double TextWidth(this TextBlock widget, string text)
{
var formattedText = new FormattedText(text, // can use arbitrary text
System.Globalization.CultureInfo.CurrentCulture,
widget.FlowDirection,
widget.FontFamily.GetTypefaces().FirstOrDefault(),
widget.FontSize,
widget.Foreground);
return formattedText.Width+widget.Padding.Left+widget.Padding.Right;
}
调整窗口大小以适应 DataGrid 内容(ugly_factor 是丑陋的解决方法;-)因为我不知道如何正确修复它,所以我将其设置为 1.3,这样我的窗口“永远不会”太小):
public static void AdjustWidthToDataGrid(this Window window, DataGrid dataGrid, double ugly_factor)
{
var max_widths = dataGrid.Columns.Select(it => window.TextWidth(it.Header as string)
* ugly_factor).ToArray();
foreach (var row in Enumerable.Range(0, dataGrid.Items.Count))
foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
{
var cell = dataGrid.GetCell(row, col);
double width = 0;
if (cell.Content is TextBlock)
width = (cell.Content as TextBlock).TextWidth();
else if (cell.Content is TextBox)
width = (cell.Content as TextBox).TextWidth();
if (cell.Content is FrameworkElement)
{
var widget = cell.Content as FrameworkElement;
width = width + widget.Margin.Left + widget.Margin.Right;
}
max_widths[col] = Math.Max(max_widths[col],
width*ugly_factor+cell.Padding.Left+cell.Padding.Right);
}
double width_diff = 0;
foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
width_diff += Math.Max(0,max_widths[col] - dataGrid.Columns[col].ActualWidth);
if (width_diff > 0)
window.Width = window.ActualWidth+ width_diff;
}
【问题讨论】:
-
我对你的调整大小逻辑有点不知所措。首先,如果您设置窗口的 SizeToContent="WidthAndHeight",那么窗口将显示为数据网格的完整大小。另一方面,如果您以某个预定义的大小显示一个窗口,并且您想在显示窗口后调整窗口大小,那么此时将大小调整为所需的数据网格是非常反直觉的。因为调整大小会从 100px 跳到 400px,但是如果我只想调整到 250px 怎么办...(假设您通过拖动窗口的角来调整大小)
-
哦,伙计,我花了整整一周的时间来编写和检查我的代码,它与 SizeToContent 相同,但方式很糟糕,现在我知道有一个选项吗? ;-) 生活具有讽刺意味... Marko,你救了我。请将您的评论重新发布为答案,我将其标记为答案。