Цель
Я хотел бы установить такой размер для DataGrid (стандартный, из WPF), чтобы все ячейки (текст) были полностью видны.У меня есть окно с DockPanel, с DataGrid в нем, поэтому, когда я изменяю размеры окна, все вложенные виджеты (DockPanel и DataGrid) изменяются соответственно.
Пример (edit-1)
Допустим, у вас есть окно шириной 100 пикселей, и у вас есть DataGrid с одним столбцом, ячейкой которого является "быстрая коричневая лиса ..." (шириной 400 пикселей).Таким образом, размер DataGrid должен быть изменен до 400 пикселей (возможно, больше из-за заполнения), а размер окна также должен быть изменен до 400 пикселей (также больше из-за заполнения).
Я не нашеллюбой стандартный способ сделать это (AFAIK WPF предоставляет способ обрезать содержимое до желаемой ширины, моя проблема совершенно противоположна), поэтому я придумала такой уродливый обходной путь, который не работает слишком хорошо.
Обходной путь
- итерация по заголовкам DataGrid (при условии, что они являются просто строками) и вычисление ширины, необходимой для текста
- итерация по строкам DataGrid для каждого столбца (при условии, что это TextBlock или TextBox) и вычислениемаксимальная ширина, необходимая для текста - добавьте горизонтальные отступы для TextBlock / TextBox и горизонтальные поля для ячейки DataGrid
- Суммируйте все различия между DataGrid ActualWidth для столбцов и максимальной шириной, вычисленной в (2)
- увеличить ширину окна на разницу, вычисленную в (3)
ПРОБЛЕМА
Я провел несколько тестов, и в некоторых случаях вычисленная ширина слишком велика (это небольшая проблема), а в некоторых случаях слишком мала.Проблема начинается с основной процедуры - вычисления требуемой ширины для TextBox / TextBlock, вычисленная ширина всегда на 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;
}