2009-05-10 11 views
17

Ho un controllo WPFcon un GridView. Mi piacerebbe ridimensionare le colonne GridView quando il contenuto delle colonne cambia.Ridimensionamento forzato delle colonne GridView all'interno di ListView

Ho diversi set di dati distinti ma quando cambio da uno all'altro, le dimensioni di ogni colonna si adattano ai dati precedenti. Mi piacerebbe aggiornare in modo dinamico. Come lo posso fare?

+2

Ho lo stesso problema. Cambia l'origine dati e le larghezze delle colonne non vengono ridimensionate. Sarei felice di impostare l'origine e chiamare un metodo AutoSizeColumns o simile. –

+0

+1, questo mi sta facendo impazzire! – Oskar

risposta

-1

è possibile misurare la stringa più lunga in pixel e quindi regolare la larghezza delle colonne di conseguenza:

Graphics graphics = this.CreateGraphics(); 
SizeF textSize = graphics.MeasureString("How long am I?", this.Font); 

Se si crea un algoritmo per il dimensionamento ogni colonna come un rapporto di queste lunghezze, si dovrebbe ottenere un buon risultato.

+0

Beh suppongo che questo non funzionerà con WPF e binding ... –

29

Infine, alcuni risultati su questo. Ho trovato un modo per fare lo stesso auto-ridimensionamento che è stato fatto inizialmente e quando il gripper su un'intestazione di colonna viene cliccato due volte.

public void AutoSizeColumns() 
{ 
    GridView gv = listView1.View as GridView; 
    if (gv != null) 
    { 
     foreach (var c in gv.Columns) 
     { 
      // Code below was found in GridViewColumnHeader.OnGripperDoubleClicked() event handler (using Reflector) 
      // i.e. it is the same code that is executed when the gripper is double clicked 
      if (double.IsNaN(c.Width)) 
      { 
       c.Width = c.ActualWidth; 
      } 
      c.Width = double.NaN; 
     } 
    } 
} 
+0

Ottima soluzione. Grazie. –

1

Non c'è un modo per eseguire il binding allo ActualWidth della colonna? Qualcosa di simile:

<GridViewColumn x:Name="column1" Width="{Binding ElementName=column1, Path=ActualWidth}" /> 

Ho provato questo e funziona solo la prima volta, a quanto pare. Nessun errore di associazione.

+0

Ho anche provato: Width = "{Binding Path = ActualWidth, RelativeSource = {x: Static RelativeSource.Self}}" – Thia

+0

Sì, si copia ActualWidth su Width, che è quindi la larghezza desiderata per sempre. Il ridimensionamento automatico è disabilitato per la prima volta. ActualWidth non cambia mai più, quindi neanche la larghezza desiderata. – ygoe

4

Sulla base della risposta di Oskars, ecco un comportamento di fusione per ridimensionare automaticamente le colonne quando il contenuto cambia.

/// <summary> 
/// A <see cref="Behavior{T}"/> implementation which will automatically resize the automatic columns of a <see cref="ListView">ListViews</see> <see cref="GridView"/> to the new content. 
/// </summary> 
public class GridViewColumnResizeBehaviour : Behavior<ListView> 
{ 
     /// <summary> 
     /// Listens for when the <see cref="ItemsControl.Items"/> collection changes. 
     /// </summary> 
     protected override void OnAttached() 
     { 
      base.OnAttached(); 

      var listView = AssociatedObject; 
      if (listView == null) 
       return; 

      AddHandler(listView.Items); 
     } 

     private void AddHandler(INotifyCollectionChanged sourceCollection) 
     { 
      Contract.Requires(sourceCollection != null); 

      sourceCollection.CollectionChanged += OnListViewItemsCollectionChanged; 
     } 

     private void RemoveHandler(INotifyCollectionChanged sourceCollection) 
     { 
      Contract.Requires(sourceCollection != null); 

      sourceCollection.CollectionChanged -= OnListViewItemsCollectionChanged; 
     } 

     private void OnListViewItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) 
     { 
      var listView = AssociatedObject; 
      if (listView == null) 
       return; 

      var gridView = listView.View as GridView; 
      if (gridView == null) 
       return; 

      // If the column is automatically sized, change the column width to re-apply automatic width 
      foreach (var column in gridView.Columns.Where(column => Double.IsNaN(column.Width))) 
      { 
       Contract.Assume(column != null); 
       column.Width = column.ActualWidth; 
       column.Width = Double.NaN; 
      } 
     } 

     /// <summary> 
     /// Stops listening for when the <see cref="ItemsControl.Items"/> collection changes. 
     /// </summary> 
     protected override void OnDetaching() 
     { 
      var listView = AssociatedObject; 
      if (listView != null) 
       RemoveHandler(listView.Items); 

      base.OnDetaching(); 
     } 
} 
+0

Questo comportamento non tiene conto del fatto che potrebbe essere necessario un po 'di tempo prima che venga calcolato il nuovo' ActualWidth'. Pertanto potrebbe accadere che "ActualWidth" sia ancora troppo piccolo per adattarsi al contenuto. – Danielku15

+0

@ Danielku15 Stai scoprendo che sta succedendo? Un piccolo campione sarebbe fantastico, quindi posso lavorare per risolvere questo problema. – Lukazoid

+1

Ho un controllo ListView associato a ObservableCollection. Ho un controllo nel mio CellTemplate che è 40x40pt. L'associazione del comportamento esegue il metodo OnListViewItemsCollectionChanged, ma ActualWidth è ancora troppo piccolo (25pt nel mio caso). Il risultato: è ritagliato. Sembra che il processo di layout non sia stato eseguito quando viene eseguito il gestore. – Danielku15

1

Se come me siete vecchi e preferisce VB.NET allora ecco il codice Oskars:

Public Sub AutoSizeColumns() 
    Dim gv As GridView = TryCast(Me.listview1.View, GridView) 
    If gv IsNot Nothing Then 
     For Each c As GridViewColumn In gv.Columns 
      If Double.IsNaN(c.Width) Then 
       c.Width = c.ActualWidth 
      End If 
      c.Width = Double.NaN 
     Next 
    End If 
End Sub 

Questa grande opera in WPF, finalmente qualcuno ha lavorato questo fuori. Grazie Oskar.

Problemi correlati