2010-11-18 4 views
11

Supponiamo che io sono un DataGrid che si definisce come questoDataGrid RowDetails problema Larghezza

<DataGrid AreRowDetailsFrozen="True" 
      ItemsSource="{Binding MyCollection}" 
      AutoGenerateColumns="False"> 
    <DataGrid.RowDetailsTemplate> 
     <DataTemplate> 
      <Border CornerRadius="5" BorderBrush="Red" 
        BorderThickness="2" Background="Black"> 
       <TextBlock Foreground="White" Text="{Binding RowDetails}" 
          TextWrapping="Wrap"/> 
      </Border> 
     </DataTemplate> 
    </DataGrid.RowDetailsTemplate> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="0" Binding="{Binding Value1}"/> 
     <DataGridTextColumn Header="1" Binding="{Binding Value2}"/> 
     <DataGridTextColumn Header="2" Binding="{Binding Value3}"/> 
     <DataGridTextColumn Header="3" Binding="{Binding Value4}"/> 
    </DataGrid.Columns> 
</DataGrid> 

E si presenta così con e senza RowDetails

alt text

Nella foto a destra ho un DataGridRow molto lungo che non esegue mai il wrapping.
È possibile ottenere che RowDetails utilizzi la stessa larghezza di DataGrid e non influenzi la larghezza stessa?

Le cose che ho provato che raggiunge il confezionamento, ma non in modo soddisfacente

  • Set Larghezza o MaxWidth sulla frontiera o TextBlock. Non molto dinamico.
  • Imposta ScrollViewer.HorizontalScrollBarVisibility = "Disabled" su DataGrid. Non molto buono quando le colonne non si adattano.

risposta

10

Questo è quello che ho finito per fare. Preferirei usare una proprietà su DataGrid per questo, ma poiché non esiste una tale proprietà avevo bisogno di una soluzione alternativa.

alt text

Per prima cosa ho appena usato ActualWidth dal padre DataGrid e rimosso una costante di 9. Questo ha funzionato in un primo momento, ma non è riuscito quando la barra di scorrimento verticale è diventato visibile, così ho dovuto usare un MultiBinding.

<DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <Border HorizontalAlignment="Left" CornerRadius="5" 
       BorderBrush="Red" BorderThickness="2" Background="Black"> 
      <Border.Width> 
       <MultiBinding Converter="{StaticResource RowDetailsWidthMultiConverter}" 
           ConverterParameter="9"> 
        <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" 
          Path="ActualWidth"/> 
        <Binding RelativeSource="{RelativeSource AncestorType={x:Type ScrollViewer}}" 
          Path="ComputedVerticalScrollBarVisibility"/> 
       </MultiBinding> 
      </Border.Width> 
      <TextBlock Foreground="White" Text="{Binding RowDetails}" TextWrapping="Wrap"/> 
     </Border> 
    </DataTemplate> 
</DataGrid.RowDetailsTemplate> 

E nel convertitore ho usato un'altra costante (16) per compensare una barra di scorrimento verticale visibile (se visibile).

public class RowDetailsWidthMultiConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     double originalWidth = (double)values[0]; 
     Visibility verticalScrollbarVisibility = (Visibility)values[1]; 
     double subtractWidth = System.Convert.ToDouble(parameter); 
     double returnWidth = originalWidth - subtractWidth; 
     if (verticalScrollbarVisibility == Visibility.Visible) 
     { 
      return returnWidth - 16; 
     } 
     return returnWidth; 
    } 
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return null; 
    } 
} 

Aggiornamento

ho migliorato sulla soluzione un po ', utilizzando ActualWidth per l'ItemsPresenter piuttosto che DataGrid (dove ActualWidth non cambia a seconda di una ScrollBar visibile), in tal modo la rimozione della bisogno di un MultiConverter e due costanti.

<DataGrid.Resources> 
    <local:SubtractConstantConverter x:Key="SubtractConstantConverter"/> 
</DataGrid.Resources> 
<DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <Border HorizontalAlignment="Left" CornerRadius="5" 
       BorderBrush="Red" BorderThickness="2" Background="Black" 
       Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsPresenter}}, 
           Path=ActualWidth, 
           Converter={StaticResource SubtractConstantConverter}, 
           ConverterParameter=6}"> 
      <TextBlock Foreground="White" Text="{Binding RowDetails}" TextWrapping="Wrap"/> 
     </Border> 
    </DataTemplate> 
</DataGrid.RowDetailsTemplate> 

SubtractConstantConverter

public class SubtractConstantConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     double originalValue = (double)value; 
     double subtractValue = System.Convert.ToDouble(parameter); 
     return originalValue - subtractValue; 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return null; 
    } 
} 
+0

con la versione aggiornata con ItemsPresenter come antenato, la barra di scorrimento verticale non è rispettata. Sottraggo 22 per evitare la barra di scorrimento orizzontale. – user2452157

2

Potrebbe essere possibile associare MaxWidth a ElementName=PART_ColumnHeadersPresenter, Path=ActualWidth o RenderSize.Width. Credo che sia la parte del Template DataGrid che visualizza le colonne quindi in teoria dovrebbe funzionare

+0

Grazie per il tuo suggerimento! Questo è abbastanza vicino a quello che ho finito per fare. –

2

Grazie Meleak, la soluzione ha funzionato bene per me. Una piccola aggiunta per noi neofiti WPF. Assicurati di dichiarare la tua classe di Convertitore come una risorsa in modo che possa essere referenziata nell'espressione Binding.

Ho inserito il mio nell'app.XAML come questo:

<Application x:Class="ISCBilling.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:conv="clr-namespace:my.application.namespace" 
      StartupUri="IscBillingWindow.xaml"> 
    <Application.Resources> 

     <conv:RowDetailsWidthMultiConverter x:Key="RowDetailsWidthMultiConverter" /> 

    </Application.Resources> 
</Application> 
+0

Grazie per la tua risposta, ho aggiunto questo alla mia soluzione aggiornata che ha rimosso la necessità di un MultiConverter. –

1

Per salvare altre persone qualche testa graffi e tempo di prova ed errori:

Dopo armeggiare con Fredrik Hedblad più recente (1/1/11) solution per qualche tempo ho pensato che il valore ConverterParameter dovrebbe essere 6 + [margine sinistro} + [margine destro] (cioè margini del contenitore esterno nel modello.) Dopo l'esame di un ingrandimento di una schermata, mi aspetto il è la larghezza della barra verticale a sinistra di ogni riga.

+0

Questa soluzione si adatta a diverse impostazioni DPI! – Ahmad

13

Le risposte qui sembravano una soluzione, quindi ho fatto qualche ricerca e ho trovato la soluzione sui forum Telerik, dal momento che usiamo RadGridView. Risultò che la soluzione funzionava anche per DataGrid.

La chiave è impostare la proprietà ScrollViewer.HorizontalScrollBarVisibility su Disabled, vedere l'esempio di seguito.

<DataGrid ScrollViewer.HorizontalScrollBarVisibility="Disabled"> 
<DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <Border> 
      <TextBlock Foreground="White" Text="{Binding RowDetails}" 
         TextWrapping="Wrap"/> 
     </Border> 
    </DataTemplate> 
</DataGrid.RowDetailsTemplate> 

Edit: Un effetto collaterale è che se le colonne ha bisogno di più spazio orizzontalmente che ci sono camera perché saranno tagliati. Quindi, se questo è un problema, questa soluzione non è ottimale.

+0

Funziona come un fascino! Grazie mille, non l'avrei capito da solo ... – Ash

+0

Questa soluzione non è scalabile quando in realtà hai bisogno di una ScrolBar orizzontale per scorrere le colonne nascoste! – Ahmad

2

Questo è quello che ho finito: legare la larghezza dei dettagli della riga alla larghezza effettiva del relatore e quindi aggiungere un bordo con uno spessore diverso per compensare la presenza/assenza di una barra di scorrimento verticale nel presentatore . Questo approccio ha funzionato perfettamente per me. Esempio xaml:

<DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <Border BorderThickness="2,2,8,2" 
       Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsPresenter}}, Path=ActualWidth}" 
       HorizontalAlignment="Left" > 
      <!-- add the row details view contents here --> 
     </Border> 
    </DataTemplate> 
</DataGrid.RowDetailsTemplate>