我在WPF中使用DataGrid并希望它缩小到仅适合其列的宽度。它很适合初始渲染。当我调整列的大小以使其更宽时,网格也会增长。但是如果我调整列的大小以使其再次变窄,我会在列的右侧获得空白区域(我可以看到列标题灰色区域扩展到列之外。
我想让数据网格用列缩小它的宽度,所以我没有得到右侧的空白区域。我试图调试代码,据我所知,问题出在DataGridCellsPanel中,但我看不到任何地方可以修复宽度测量。
任何帮助都将不胜感激。
答案 0 :(得分:3)
我有一段时间没遇到这个问题了,我对此感到非常生气,以至于我为它做了一个丑陋的修复。它不漂亮,但它完成了工作。首先,当水平ScrollBar不可见时,这只是一个问题所以我们需要引用它。一旦加载了所有DataGridColumns(在我的情况下,所有在Xaml中,所以在Loaded事件中)都必须运行此代码,并且不考虑添加/删除DataGridColumns,但这是一个简单的修复。
<DataGrid Name="c_dataGrid"
Loaded="c_dataGrid_Loaded"
...>
<DataGrid.Columns>
<DataGridTextColumn ..."/>
<DataGridTextColumn ..."/>
<!-- ... -->
然后在Loaded EventHandler中,我们获取DataGrid ScrollViewer,并为DataGrid中每个DataGridColumn的ActualWidthProperty中的更改添加一个侦听器。
private ScrollViewer m_dataGridScrollViewer = null;
private void c_dataGrid_Loaded(object sender, RoutedEventArgs e)
{
m_dataGridScrollViewer = GetVisualChild<ScrollViewer>(c_dataGrid);
DependencyPropertyDescriptor dependencyPropertyDescriptor =
DependencyPropertyDescriptor.FromProperty(DataGridColumn.ActualWidthProperty, typeof(DataGridColumn));
if (dependencyPropertyDescriptor != null)
{
foreach (DataGridColumn column in c_dataGrid.Columns)
{
dependencyPropertyDescriptor.AddValueChanged(column, DataGridColumn_ActualWidthChanged);
}
}
}
然后我们从所有DataGridColumns的大小计算DataGrid的大小,并添加一个8.0的常量(通常是差异)。
private void DataGridColumn_ActualWidthChanged(object sender, EventArgs e)
{
if (m_dataGridScrollViewer != null)
{
if (m_dataGridScrollViewer.ComputedHorizontalScrollBarVisibility != Visibility.Visible)
{
double dataGridWidth = 8.0;
foreach (DataGridColumn column in c_dataGrid.Columns)
{
dataGridWidth += column.ActualWidth;
}
c_dataGrid.Width = dataGridWidth;
}
else
{
c_dataGrid.Width = double.NaN;
}
}
}
如果您想出更好的方法,请告诉我:)
public static T GetVisualChild<T>(object parent) where T : Visual
{
DependencyObject dependencyObject = parent as DependencyObject;
return InternalGetVisualChild<T>(dependencyObject);
}
private static T InternalGetVisualChild<T>(DependencyObject parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
答案 1 :(得分:2)
这是一个很好的解决方案。我稍微调整了它,以便它设置MaxWidth属性。这解决了网格扩展超出视觉父级约束的问题。我还将其转换为行为,以便更好地封装它。
这就是我最终的目标。
public class UpdateWidthOnColumnResizedBehavior : Behavior<DataGrid>
{
private static readonly DependencyPropertyDescriptor Descriptor;
static UpdateWidthOnColumnResizedBehavior()
{
Descriptor = DependencyPropertyDescriptor.FromProperty(DataGridColumn.ActualWidthProperty, typeof(DataGridColumn));
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Columns.CollectionChanged += OnColumnsCollectionChanged;
foreach (var column in AssociatedObject.Columns)
{
AddListener(column);
}
}
void OnColumnsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var column in e.NewItems.OfType<DataGridColumn>())
{
AddListener(column);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var column in e.OldItems.OfType<DataGridColumn>())
{
RemoveListener(column);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (var column in e.NewItems.OfType<DataGridColumn>())
{
AddListener(column);
}
foreach (var column in e.OldItems.OfType<DataGridColumn>())
{
RemoveListener(column);
}
break;
}
}
protected override void OnDetaching()
{
base.OnDetaching();
foreach (var column in AssociatedObject.Columns)
{
RemoveListener(column);
}
}
private void AddListener(DataGridColumn column)
{
Descriptor.AddValueChanged(column, ResizeGrid);
}
private void RemoveListener(DataGridColumn column)
{
Descriptor.RemoveValueChanged(column, ResizeGrid);
}
private void ResizeGrid(object sender, EventArgs e)
{
var columnsWidth = AssociatedObject.Columns.Sum(c => c.ActualWidth);
AssociatedObject.MaxWidth = columnsWidth + 2;
AssociatedObject.InvalidateMeasure();
}
}
我仍然需要解决两个网格的宽度协调问题,但它看起来适用于一个网格。
答案 2 :(得分:0)
这两种方法似乎都存在轻微问题。当我向左拖动最左边的列时,整个网格会被调整大小/滚动到内部(不幸的是,我没有足够的声誉来发布图像)。
所以我修改了jjrdk ResizeGrid函数,因此它计算了最后一列的宽度并将其一直延伸到左边。必须将网格HorizontalAlignment和HorizontalContentAlignment设置为 HorizontalAlignment.Stretch。
void ResizeGrid(object sender, EventArgs e)
{
var scroll = ExTreeHelper.FindVisualChild<ScrollViewer>(AssociatedObject);
if (scroll != null && null != AssociatedObject.Columns && AssociatedObject.Columns.Count > 0)
{
var lastColumn = AssociatedObject.Columns.Last();
double dataGridWidth = AssociatedObject.Columns.Sum(c => c.ActualWidth) + 2.0;
if (scroll.ComputedHorizontalScrollBarVisibility != Visibility.Visible)
{
RemoveListener(lastColumn);
AssociatedObject.Columns.Last().Width =
AssociatedObject.Columns.Last().Width.DisplayValue + scroll.ViewportWidth - dataGridWidth;
AssociatedObject.Width = dataGridWidth + scroll.ViewportWidth - dataGridWidth;
AddListener(lastColumn);
}
else
{
AssociatedObject.HorizontalAlignment = HorizontalAlignment.Stretch;
AssociatedObject.HorizontalContentAlignment = HorizontalAlignment.Stretch;
AssociatedObject.Width = double.NaN;
}
} }
我唯一的问题是滚动条始终存在,即使所有列都适合。
还有一个问题,当所有列都向左折叠时,它会开始闪烁。
有什么可以做的,真正摆脱这个空白区域吗?
莱昂