2010-11-15 3 views
5

Я использую DataGrid в WPF и хочу, чтобы он уменьшался, чтобы соответствовать ширине его столбцов. Он делает это хорошо для первоначального рендеринга. Когда я изменяю размер столбца, чтобы сделать его более широким, сетка также растет. Но если я изменил размер столбца, чтобы сделать его более узким, я получаю пустое пространство справа от моей колонки (и я вижу, что серая область заголовка столбца расширяется за столбцами.WPF DataGrid не сжимается при уменьшении ширины столбца

Я хотел бы иметь данные сетка сжимает его ширину столбцами, поэтому я не получаю пустое пространство справа. Я пытался отладить код, и насколько я вижу, проблема в DataGridCellsPanel, но я не вижу ничего, что можно исправить измерение ширины.

Любая помощь будет оценена.

ответ

3

Я имел эту проблему на некоторое время назад, и я получаю так раздражен этим, что я сделал некрасивый исправление для него. это не красиво, но это становится работа. Во-первых, t его проблема только в том случае, когда горизонтальный ScrollBar невидим, поэтому нам нужна ссылка на него. Этот код должен запускаться после загрузки всех DataGridColumns (в моем случае, все в Xaml, так что событие Loaded), и это не требует добавления/удаления DataGridColumns, но это простое исправление.

<DataGrid Name="c_dataGrid" 
      Loaded="c_dataGrid_Loaded" 
      ...> 
    <DataGrid.Columns> 
     <DataGridTextColumn ..."/> 
     <DataGridTextColumn ..."/> 
     <!-- ... --> 

Тогда в Loaded EventHandler мы получаем DataGrid ScrollViewer и добавить слушателя изменений в ActualWidthProperty каждого DataGridColumn в DataGrid.

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); 
     } 
    } 
} 

И тогда мы вычислить размер DataGrid от размера всех DataGridColumns и добавить постоянную 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; 
} 
+0

Это прекрасное решение. Я немного изменил его, чтобы вместо этого установить свойство MaxWidth. Это решает проблему сетки, расширяющейся за пределами ограничений визуального родителя. Вместо этого я преобразовал его в поведение, чтобы лучше его инкапсулировать. – jjrdk

+0

Кроме того, если DataGridColumn_ActualWidthChanged не вызывается, убедитесь, что вы используете Microsoft.Windows.Controls.DataGridColumn, а не System.Windows.Controls.DataGridColumn, когда вы получаете DependencyPropertyDescriptor. – Monsignor

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(); 
     } 
    } 

Я до сих пор есть некоторые вещи, чтобы сглаживать о ширине координации двух сеток, но он смотрит на работу на один.

+0

Выглядит отлично, попробуй это в следующий раз, когда мне это понадобится! –

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; 
      } 
     }   } 

Единственная проблема, с которой я столкнулся, заключается в том, что полоса прокрутки всегда существует, даже если все столбцы подходят.

Есть еще одна проблема, когда все столбцы рушится влево, она начинает мерцать.

Есть ли что-нибудь, что можно сделать, чтобы действительно избавиться от этого пробела?

Leon

Смежные вопросы