2010-11-15 20 views
5

Estoy usando un DataGrid en WPF y quiero que se contraiga para que solo se ajuste al ancho de sus columnas. Lo hace muy bien para la representación inicial. Cuando cambio el tamaño de una columna para hacerlo más ancha, la cuadrícula también crece. Pero si cambio el tamaño de la columna para volverla más estrecha, obtengo un espacio en blanco en el lado derecho de mi columna (y veo que el área del encabezado gris se extiende más allá de las columnas.WPF DataGrid no se contrae cuando el ancho de la columna se contrae

Me gustaría tener los datos la cuadrícula reduce su ancho con las columnas, así que no obtengo el espacio en blanco a la derecha. He intentado depurar el código y, por lo que puedo ver, el problema está en el DataGridCellsPanel, pero no veo ningún lugar donde corregirlo. la medida de ancho.

Cualquier ayuda sería muy apreciada.

Respuesta

3

que tenía ese problema a un tiempo atrás y yo estaba tan molesto por lo que hice una solución fea para él. no es bonito, pero se pone el trabajo hecho. Primero, t Esto es solo un problema cuando el ScrollBar Horizontal es invisible, así que vamos a necesitar una referencia al mismo. Este código deberá ejecutarse una vez que se hayan cargado todos los DataGridColumns (en mi caso, todo en Xaml, por lo que el evento Loaded) y no tiene en cuenta la adición o eliminación de DataGridColumns, pero es una solución fácil.

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

Luego, en el manejador de sucesos Loaded obtenemos la cuadrícula de datos ScrollViewer y añadir un detector de cambios en la ActualWidthProperty de cada DataGridColumn en la cuadrícula de datos.

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

Y entonces se calcula el tamaño de la cuadrícula de datos desde el tamaño de todos los DataGridColumns y añadir una constante de 8,0 (que es la diferencia normalmente).

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

Si usted viene con una mejor forma de hacer esto, entonces hágamelo saber :)

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

Esa es una buena solución. Lo modifiqué ligeramente para que establezca la propiedad MaxWidth en su lugar. Esto resuelve el problema de la cuadrícula expandiéndose más allá de las limitaciones del padre visual. También lo convertí en un comportamiento para encapsularlo mejor. – jjrdk

+0

Además, si no se está llamando a DataGridColumn_ActualWidthChanged, asegúrese de utilizar Microsoft.Windows.Controls.DataGridColumn y no System.Windows.Controls.DataGridColumn cuando obtenga DependencyPropertyDescriptor. – Monsignor

2

Esa es una buena solución. Lo modifiqué ligeramente para que establezca la propiedad MaxWidth en su lugar. Esto resuelve el problema de la cuadrícula expandiéndose más allá de las limitaciones del padre visual. También lo convertí en un comportamiento para encapsularlo mejor.

Esto es lo que terminé con.

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

todavía tienen algunas cosas para limar acerca de la coordinación anchura de dos rejillas, pero parece que trabajar para uno.

+0

Se ve muy bien, ¡intentaré esto la próxima vez que lo necesite! –

0

Parece que hay un pequeño problema con ambos enfoques. Cuando arrastro la columna que está más a la izquierda hacia la derecha, toda la cuadrícula se redimensiona/rueda hacia adentro (desafortunadamente no tengo suficiente reputación para publicar la imagen).

Así que he modificado la función jjrdk ResizeGrid, por lo que se calcula el último ancho de la columna y se extiende hasta la izquierda. La cuadrícula HorizontalAlignment y HorizontalContentAlignment debe establecerse en 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; 
      } 
     }   } 

El único problema que tengo, es que la barra de desplazamiento siempre está ahí, incluso si todas las columnas ha sido conveniente.

Todavía hay otro problema, cuando todas las columnas están contraídas a la izquierda, comienza a parpadear.

¿Hay algo que se pueda hacer, realmente deshacerse de este espacio en blanco?

Leon

Cuestiones relacionadas