2010-11-15 18 views
5

Używam DataGrid w WPF i chcę, aby zmniejszała się tylko do szerokości kolumn. Robi to ładnie podczas wstępnego renderowania. Kiedy zmieniam rozmiar kolumny, aby ją poszerzyć, rośnie także siatka. Ale jeśli zmieniam rozmiar kolumny, aby była węższa, otrzymam białe pole po prawej stronie mojej kolumny (i widzę, że szary obszar nagłówka kolumny jest rozciągnięty poza kolumny:WPG DataGrid nie kurczy się, gdy szerokość kolumny się zmniejsza

Chciałbym mieć dane grid zmniejsz jego szerokość za pomocą kolumn, więc nie otrzymuję białej spacji po prawej stronie. Próbowałem debugować kod i o ile widzę problem jest w DataGridCellsPanel, ale nie widzę żadnego miejsca do naprawienia pomiar szerokości.

Każda pomoc będzie mile widziane.

Odpowiedz

3

miałem ten problem na jakiś czas z powrotem, a ja się tak zły przez to, że zrobiłem brzydki poprawkę dla niego. to nie jest ładna, ale robi zadanie po pierwsze jego jest tylko problem, gdy poziomy pasek przewijania jest niewidoczny, więc będziemy potrzebować odniesienia do niego. Ten kod będzie musiał zostać uruchomiony po załadowaniu wszystkich DataGridColumns (w moim przypadku wszystkie w Xaml, więc w załadowanym zdarzeniu) i nie bierze pod uwagę dodawania/usuwania DataGridColumns, ale jest to łatwa łatwa.

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

Następnie w Loaded EventHandler otrzymujemy DataGrid ScrollViewer i dodać detektor zmian w ActualWidthProperty każdego DataGridColumn w 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); 
     } 
    } 
} 

Następnie obliczyć rozmiaru siatki danych z rozmiaru wszystkich DataGridColumns i dodać stałej 8,0 (co jest zwykle różnica).

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

Jeśli wymyślić lepszy sposób to daj mi znać :)

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

To dobre rozwiązanie. Zmodyfikowałem go nieznacznie, aby zamiast tego ustawić właściwość MaxWidth. To rozwiązuje problem siatki wychodzącej poza ograniczenia wizualnego rodzica. Przekształciłem go również w zachowanie, aby lepiej je enkapsulować. – jjrdk

+0

Ponadto, jeśli DataGridColumn_ActualWidthChanged nie jest wywoływana, upewnij się, że używasz Microsoft.Windows.Controls.DataGridColumn, a nie System.Windows.Controls.DataGridColumn, gdy otrzymujesz DependencyPropertyDescriptor. – Monsignor

2

To piękny rozwiązanie. Zmodyfikowałem go nieznacznie, aby zamiast tego ustawić właściwość MaxWidth. To rozwiązuje problem siatki wychodzącej poza ograniczenia wizualnego rodzica. Przekształciłem go również w zachowanie, aby lepiej je enkapsulować.

Tak właśnie skończyłem.

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

Nadal mam kilka rzeczy do wypróbowania na temat koordynacji szerokości dwóch sieci, ale wygląda na to, że działa.

+0

Wygląda świetnie, spróbuję tego następnym razem, gdy będę tego potrzebować! –

0

wydaje się, że istnieje niewielki problem z obydwoma metodami. Kiedy przeciągam lewą kolumnę w prawo, cała siatka jest zmieniana/wsuwana do środka (niestety nie mam wystarczającej reputacji, aby opublikować obraz).

Tak więc zmodyfikowałem funkcję Jjrdk ResizeGrid, aby obliczyć ostatnią szerokość kolumny i rozszerzyć ją do końca w lewo. Siatka HorizontalAlignment i HorizontalContentAlignment muszą być ustawione na 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; 
      } 
     }   } 

Jedynym problemem, jaki mam, jest to, że pasek przewijania jest zawsze tam, nawet jeśli wszystkie kolumny zostały dopasowane.

Jest jeszcze inny problem, gdy wszystkie kolumny są zwinięte w lewo, zaczyna migać.

Czy jest coś, co można zrobić, aby naprawdę pozbyć się tej białej przestrzeni?

Leon

Powiązane problemy