2011-02-14 9 views
19

Tengo un WPF DataGrid que contiene algunos datos. Me gustaría establecer el ancho de las columnas de modo que el contenido encaje y nunca se recorta (en cambio, una barra de desplazamiento horizontal debería ser visible). Además, quiero que el DataGrid llene todo el lugar disponible (estoy trabajando con un DockPanel). Estoy utilizando el siguiente código (simplificado):¿Cómo puedo establecer el ancho de un DataGridColumn para que se ajuste a los contenidos ("Auto"), pero complete por completo el espacio disponible para el DataGrid en MVVM?

<DataGrid ItemsSource="{Binding Table}"> 
    <DataGrid.Columns> 
     <DataGridTextColumn MinWidth="100" Width="Auto" Header="Column 1" Binding="{Binding Property1}" /> 
     <DataGridTextColumn MinWidth="200" Width="Auto" Header="Column 2" Binding="{Binding Property2}" /> 
    </DataGrid.Columns> 
</DataGrid> 

Al parecer, esto no funciona fuera de la caja con Width="Auto", ya que siempre se ve algo como esto:

DataGrid: only the first part of the row is marked as "selected"

Esto, obviamente, se ve feo. Me gustaría tener toda la fila seleccionada, o, lo que sería mucho mejor, las columnas para llenar todo el ancho, pero como se puede ver, esto no funciona.

En su lugar, si utilizo Width="*", el contenido de las columnas se recorta, lo que es aún peor para mí.

Encontré un similar question here, y una solución fue publicada allí. Esto puede funcionar, pero estoy trabajando con el patrón MVVM, por lo que el ItemsSource se actualiza en el ViewModel y no puedo pensar en una forma de hacerlo a partir de allí, porque no puedo acceder a la propiedad DataGridColumn del ActualWidth. Además, me gustaría hacerlo solo en XAML si es posible.

Agradeceria cualquier ayuda. ¡Gracias!

Editar: Como todavía no tengo ni idea de qué hacer al respecto, comienzo una pequeña recompensa. Estaría muy feliz con una sugerencia de lo que se podría hacer con mi problema. ¡Gracias de nuevo!

Editar 2: Después de la respuesta de saus, pensé nuevamente en las opciones. El problema es que necesito actualizar las propiedades Width y MinWidth también durante la ejecución de la aplicación, por lo que no solo después de cargar la ventana. Ya he intentado hacer algo como

column.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); 
column.MinWidth = column.ActualWidth; 
column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); 

en algún evento que se dispara cuando el ItemsSource subyacente de la DataGrid es la actualización. Sin embargo, esto no funciona, ya que la propiedad ActualWidth no parece cambiar después de configurar el Width en Auto. ¿Existe una opción para "volver a pintar" de alguna manera para obtener la propiedad ActualWidth actualizada? ¡Gracias!

+0

No estoy seguro de entender lo que quiere hacer aquí. Si el ancho de la columna se hace más ancho que el 'DataGrid', ¿desea una barra de desplazamiento vertical y no desea que el texto se ajuste? ¿Te refieres a una barra de desplazamiento horizontal? De lo contrario, esto no tiene sentido para mí, pero tal vez estoy lento aquí :) –

+1

¡Gracias por la pista! Por supuesto que me refería a una barra de desplazamiento horizontal, de lo contrario no tendría ningún sentido ;-) –

Respuesta

2

Si desea que la columna para no cortar sus datos, añadir lo siguiente a la definición de la ventana/control de usuario:

xmlns:System="clr-namespace:System;assembly=mscorlib" 

Luego de la anchura de las columnas se pueden utilizar para siguiente.

Width="{x:Static System:Double.NaN}" 

Esto hace que la columna siempre crezca lo suficiente para acomodar el valor más largo en la columna.

Como el código anterior no funcionaba en la cuadrícula de datos, ¿qué pasa con la adición de un ScrollViewer alrededor de la cuadrícula de datos como esto:

 <ScrollViewer HorizontalScrollBarVisibility="Auto" 
        VerticalScrollBarVisibility="Auto"> 
     <DataGrid ItemsSource="{Binding Table}" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn MinWidth="10" Width="Auto" Header="Column 1" Binding="{Binding Property1}" /> 
       <DataGridTextColumn MinWidth="200" Width="*" Header="Column 2" Binding="{Binding Property2}" />      
      </DataGrid.Columns> 
     </DataGrid> 
    </ScrollViewer> 
+1

Gracias por la respuesta. Sin embargo, obtengo una 'XamlParseException' luego de agregar eso. Además, creo que esto terminaría mostrando exactamente el mismo comportamiento que establecer 'Width' a' "Auto" '(en realidad, creo que' "Auto" 'está representado internamente como' Double.NaN'). –

+0

Lo había usado en GridViews y funcionó de maravilla para dimensionar dinámicamente las columnas. Lo intenté con DataGrid esta mañana y obtuve el mismo error de Xaml. –

+1

¿Entonces recibiste un error pero decidiste publicar tu respuesta? – David

4

Uso TextBlock con ajuste de texto dentro de la columna de plantilla:

<DataGrid ItemsSource="{Binding Table}">  
    <DataGrid.Columns>   
     <DataGridTextColumn MinWidth="100" Width="Auto" Header="Column 1" 
          Binding="{Binding Property1}" />   
     <DataGridTemplateColumn Width="*" Header="Column 2"> 
      <DataGridTemplateColumn.CellTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding Property2}" TextWrapping="Wrap" /> 
       </DataTemplate> 
      </DataGridTemplateColumn.CellTemplate> 
     </DataGridTemplateColumn> 
    </DataGrid.Columns> 
</DataGrid> 
+0

Gracias por su sugerencia, pero no quiero ajustar el texto. Como mencioné anteriormente, me gustaría obtener una barra de desplazamiento vertical tan pronto como el texto se ensanche demasiado. –

+0

El objetivo de las columnas con plantilla es que puede usar el control que se ajuste a sus necesidades dentro de DataTemplate, por ejemplo

+3

no quiero tener una barra de desplazamiento en la columna específica, sino una para toda la cuadrícula de datos que también aparece si configuro el ancho de las columnas en "Auto" y el espacio no es suficiente ... se vería muy mal si tiene una barra de desplazamiento en cada celda ... –

1

¿qué tal esto:

para MinWidth de sus columnas, configura un enlace al ancho de ScrollContent de dataGrid, con un convertidor que divide este ancho por nu mber de columnas

necesita un código para el convertidor, pero esto mantendría intacta su estructura MVVM.

podría ser una posibilidad remota, pero no tuvimos el tiempo para probarlo.

Edité: Puse un poco más de reflexión en este y en otro pb: no funcionará bien si tiene, por ejemplo, una gran columna y algunas pequeñas. Supuse que todos los cols tienen el mismo ancho, lo que obviamente no es el caso aquí.

Es posible que desee explorar de esta manera sin embargo. Usar enlaces en los Anchos con convertidores es lo único que se me ocurre que podría funcionar: dado que básicamente tienes 2 condiciones para tener en cuenta al calcular el ancho de una columna, no habrá una manera fácil de hacerlo.

+0

bien, gracias por el idea, voy a pensar en eso. Sin embargo, de hecho, tengo una columna que se vuelve mucho más amplia que las otras columnas, por lo que no funcionará con la primera sugerencia. Creo que tienes razón en que necesito usar enlaces para el ancho de las columnas (eso es lo que también pienso), pero aún será un desafío encontrar el ancho/ancho correcto para cada columna ^^ –

+0

ciertamente lo hará . ^^ Si puedo agregar un consejo: no use la propiedad MinWidth junto con la propiedad Ancho si puede evitarlo. Puede provocar dolores de cabeza masivos. por ejemplo: configure el minWidth en 100, luego el ancho en 80, y el ancho del control será 80: el ancho toma el minWidth si lo configura por programa ... – David

29

Sugeriría usar la solución a la que se ha vinculado. Funciona. En el código subyacente de la vista, añadir el siguiente al constructor después de InitializeComponent():

Griddy.Loaded += SetMinWidths; // I named my datagrid Griddy 

y definir SetMinWidths como:

public void SetMinWidths(object source, EventArgs e) 
     { 
      foreach (var column in Griddy.Columns) 
      { 
       column.MinWidth = column.ActualWidth; 
       column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); 
      } 
     } 

Estoy asumiendo que la razón por la que no quiere utilizar esta solución es que usted cree que MVVM prohíbe el código en el código subyacente. Pero dado que esto es completamente lógico de vista específica, creo que está justificado en este caso. Todo el asunto "MVVM prohíbe el código en el código subyacente" es un poco erróneo.

Pero si usted está obligado por las guías de estilo, o si desea esta lógica esté disponible para todos los DataGrids en su aplicación, se puede hacer un comportamiento adjunto que hace el trabajo de esta manera:

public class SetMinWidthToAutoAttachedBehaviour 
    { 
     public static bool GetSetMinWidthToAuto(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(SetMinWidthToAutoProperty); 
     } 

     public static void SetSetMinWidthToAuto(DependencyObject obj, bool value) 
     { 
      obj.SetValue(SetMinWidthToAutoProperty, value); 
     } 

     // Using a DependencyProperty as the backing store for SetMinWidthToAuto. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty SetMinWidthToAutoProperty = 
      DependencyProperty.RegisterAttached("SetMinWidthToAuto", typeof(bool), typeof(SetMinWidthToAutoAttachedBehaviour), new UIPropertyMetadata(false, WireUpLoadedEvent)); 

     public static void WireUpLoadedEvent(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var grid = (DataGrid)d; 

      var doIt = (bool)e.NewValue; 

      if (doIt) 
      { 
       grid.Loaded += SetMinWidths; 
      } 
     } 

     public static void SetMinWidths(object source, EventArgs e) 
     { 
      var grid = (DataGrid)source; 

      foreach (var column in grid.Columns) 
      { 
       column.MinWidth = column.ActualWidth; 
       column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); 
      } 
     } 
    } 

y luego para cualquier cuadrícula de datos que desea aplicar a este comportamiento, agregue lo siguiente:

<DataGrid ItemsSource="{Binding Table}" local:SetMinWidthToAutoAttachedBehaviour.SetMinWidthToAuto="true"> 

Y entonces su conciencia, así como su código subyacente, será claro.

+3

Hola, muchas gracias por eso! En realidad, no creo que ver completamente cosas específicas no deba estar en el código subyacente. El problema es más bien que el contenido de 'DataGrid' cambia en ViewModel, por lo que la vista no sabe cuándo tiene que volver a llamar a' SetMinWidths'. ¿Tal vez habría una manera de que DataGrid cambie tan pronto como se llame a mi método 'NotifyPropertyChanged'? Creo que es el mismo problema con el comportamiento adjunto, pero probablemente encuentre una manera de solucionarlo. Volveremos con más información pronto. ¡Gracias de nuevo! –

+0

ver mi publicación, la edité: Desafortunadamente, no conseguí que funcionara así. Por las razones, ver arriba. –

+1

¿Necesitamos cancelar la suscripción a ese evento para evitar fugas de memoria? – Den

0

Fuerza de la última columna para tomar todo el espacio restante en la cuadrícula de datos

grid.Columns[grid.Columns.Count -1].Width = new 
        DataGridLength(250, DataGridLengthUnitType.Star); 
1

he añadido el Event a la DataGrid que redefinir su anchura con respecto a la anchura real de la DataGrid:

private static void OnLoaded(object sender, RoutedEventArgs e) 
    { 
     DataGrid dg = sender as DataGrid; 
     foreach (var column in dg.Columns) 
     { 
      column.Width = new DataGridLength(dg.ActualWidth/dg.Columns.Count, DataGridLengthUnitType.Pixel); 
     } 
    } 

La línea:

column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); 

fue absolutamente indemne. La definición de DataGridLengthUnitType.Star reduce el ancho de las columnas a su ancho mínimo, y hace que su ancho sea estático y no editable.

Cuestiones relacionadas