2014-08-29 10 views
5

Ho un controllo Grid che è proporzionato utilizzando la stella e.g.Come si ottengono le colonne Griglia WPF definite con la stella per ritagliare il contenuto?

<Grid.ColumnDefinitions> 
    <ColumnDefinition Width="50*" /> 
    <ColumnDefinition Width="100*" /> 
    <ColumnDefinition Width="50*" /> 
</Grid.ColumnDefinitions> 

mettendo però un lungo TextBlock nella griglia che trabocca provoca le proporzioni di essere sconvolto. per esempio.

<TextBlock Text="Foo" Grid.Column="0" /> 
<TextBlock Text="Some long text here which overflows" Grid.Column="1" /> 
<TextBlock Text="Foo" Grid.Column="2" /> 

Ciò fa sì che la colonna centrale sia più del doppio degli altri due. Come mantenere le proporzioni specificate? È possibile ritagliare il contenuto?

Ho impostato TextTrimming="CharacterEllipsis" su TextBlocks ma senza fortuna.

Modifica

Fondamentalmente sembra, la griglia è all'interno di un DataTemplate, incollare il seguente di osservare il comportamento,

<!-- FallbackValue is just a quick hack to get some rows to show at design-time --> 
<ListBox ItemsSource="{Binding Foo, FallbackValue=1234}" 
      HorizontalContentAlignment="Stretch"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="50*" /> 
         <ColumnDefinition Width="100*" /> 
         <ColumnDefinition Width="50*" /> 
        </Grid.ColumnDefinitions> 
        <TextBlock Text="Foo" Grid.Column="0" /> 
        <TextBlock Text="Some long text here which overflows" TextTrimming="CharacterEllipsis" Grid.Column="1" /> 
        <TextBlock Text="Foo" Grid.Column="2" /> 
       </Grid> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

Il motivo per cui questo è importante è che ho un altro Grid come un fratello di ListBox che visualizza le "intestazioni" per le colonne mostrate nello ListBox come segue,

<Grid> 
    ... Headers and column definitions here 
</Grid> 

<ListBox ...> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       ... Matching column definitions here 
      </Grid> 
     </DateTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

e quindi è importante che le colonne corrispondano.

ho cercato di impegnare la ColumnDefinitions all'interno del DataTemplate all'esterno GridColumnDefinitions ma non posso ottenere facilmente un riferimento legarsi ad esso.

+2

io non sono in grado di riprodurre con la creazione di un nuovo WPF app e incollare questo XAML nella finestra. Sei sicuro di aver messo tutti i tuoi modelli/codice qui? Potrebbe esserci uno stile/trigger/modello/animazione che interferisce. Cerca di fornire una rappresentazione minima del problema. –

+0

solitamente la larghezza 'auto' ha tale problema,' * 'limiterà la larghezza a meno che non ci sia una larghezza automatica in uno dei suoi contenitori principali. – pushpraj

+1

L'ho riprodotto e ritaglia correttamente con 'TextTrimming = "CharacterEllipsis"' – AxdorphCoder

risposta

5

Questo è uno dei problemi più fastidiosi con WPF. Poiché lo spazio disponibile ceduto alla griglia basata su modelli è infinito, il contenuto effettivo occuperà tutto lo spazio che desidera.

Il modo più semplice consiste nel fissare una certa larghezza alla griglia, ma ciò risolve solo le situazioni in cui non c'è ridimensionamento.

Mentre si desidera allungare la dimensione del ListBox (larghezza, nello specifico), sfortunatamente suppongo che non ci sia una soluzione migliore se non un convertitore personalizzato.

Ecco la mia soluzione:

<Window.Resources> 
    <local:MyConv x:Key="cv1" /> 
</Window.Resources> 
<Grid> 
    <ListBox 
     ItemsSource="{Binding Foo, FallbackValue=1234}" 
     HorizontalContentAlignment="Stretch" 
     > 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Grid Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}, Converter={StaticResource cv1}}"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="50*" /> 
         <ColumnDefinition Width="100*" /> 
         <ColumnDefinition Width="50*" /> 
        </Grid.ColumnDefinitions> 
        <TextBlock Text="Foo" Grid.Column="0" /> 
        <TextBlock Text="Some long text here which overflows" TextTrimming="CharacterEllipsis" Grid.Column="1" /> 
        <TextBlock Text="Foo" Grid.Column="2" /> 
       </Grid> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 

e il convertitore:

class MyConv : IValueConverter 
{ 
    public object Convert(
     object value, 
     Type targetType, 
     object parameter, 
     System.Globalization.CultureInfo culture 
     ) 
    { 
     return (double)value - 30.0; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 
0

Set

TextTrimming="CharacterEllipsis" 

sul TextBlock.

Funziona per me. Come hai definito la colonna centrale dovrebbe essere il doppio della dimensione dell'altro.

1

Anche se questo è un vecchio post sto aggiungendo i miei risultati come potrebbe essere rilevante per le altre persone che leggono questo post. Ho avuto un problema simile (le mie colonne * non dividevano la larghezza in modo uniforme come ci si aspettava più, erano semplicemente dimensionate in base al contenuto). La causa principale era che avevo una ListView con un'OrigineSource collegata ad una Lista. ListView in WPF contiene ScrollViewer e ScrollViewer non ha una larghezza fissa. Senza una larghezza fissa, una griglia non può determinare correttamente la larghezza da assegnare a una colonna * e passa a un altro metodo di dimensionamento.

Soluzione io uso un ItemsControl che non contiene uno ScrollViewer e quindi la larghezza è noto che permette la griglia per dimensionare correttamente è colonne.

Per maggiori dettagli su come esattamente la griglia gestisce è dimensionamento ti suggerisco di decompilare la classe griglia e dare un'occhiata al seguente metodo:

protected override Size MeasureOverride(Size constraint) 

Questa è la mia MainWindow.xaml dalla mia applicazione di test (commento il ListView per vedere la differenza di comportamento):

<Window x:Class="WPFSO.MainWindow" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:wpfso="clr-namespace:WPFSO"   
      Title="MainWindow" Height="150" Width="525"> 
     <Window.DataContext> 
      <wpfso:SharedSizeScopeViewModel /> 
     </Window.DataContext> 
     <Window.Resources> 
      <DataTemplate DataType="{x:Type wpfso:TestViewModel}"> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="Auto" /> 
         <ColumnDefinition Width="*" x:Name="SecondColumn" /> 
         <ColumnDefinition Width="Auto" /> 
         <ColumnDefinition Width="*" x:Name="FourthColumn" /> 
        </Grid.ColumnDefinitions> 

        <TextBlock Grid.Column="0" Text="{Binding Name}" /> 
        <TextBlock Grid.Column="1" Background="LightGray" Text="{Binding Name2}"/>     
        <TextBlock Grid.Column="2" Text="{Binding Name3}"/> 
        <TextBlock Grid.Column="3" Background="Orange" Text="{Binding Name4}"/> 

        <!--<TextBlock Grid.Column="1" Background="Blue" HorizontalAlignment="Stretch" /> 
        <TextBlock Grid.Column="3" Background="Orange" HorizontalAlignment="Stretch" />--> 
       </Grid> 
      </DataTemplate> 

      <DataTemplate x:Key="MainDataTemplate" DataType="wpfso:SharedSizeScopeViewModel" > 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="Auto" /> 
         <ColumnDefinition Width="*" /> 
         <ColumnDefinition Width="Auto" /> 
         <ColumnDefinition Width="*" /> 
        </Grid.ColumnDefinitions> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="Auto" /> 
         <RowDefinition Height="Auto" /> 
         <RowDefinition Height="Auto" /> 
        </Grid.RowDefinitions> 

        <CheckBox Grid.Row="0" Grid.ColumnSpan="4" HorizontalAlignment="Left" FlowDirection="RightToLeft" Margin="0,0,0,25"> 
         <TextBlock FlowDirection="LeftToRight" Text="Show differences" Style="{StaticResource LabelStyle}" /> 
        </CheckBox> 

        <TextBlock Grid.Row="1" Grid.Column="0" Text="PropertyName" Style="{StaticResource LabelStyle}" /> 
        <TextBlock Grid.Row="1" Grid.Column="1" Text="Previous value" Style="{StaticResource LabelStyle}" /> 
        <TextBlock Grid.Row="1" Grid.Column="3" Text="Current value" Style="{StaticResource LabelStyle}" /> 

        <ListView Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" ItemsSource="{Binding Entries}" HorizontalAlignment="Stretch" Margin="0" HorizontalContentAlignment="Stretch"/> 
       </Grid> 
      </DataTemplate> 
     </Window.Resources> 
     <Grid Name="RootGrid"> 

      <ItemsControl ItemsSource="{Binding Entries}" /> 
      <!--<ListView ItemsSource="{Binding Entries}" />--> 

     </Grid> 
    </Window> 

The ViewModels used during this test: 

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 

namespace WPFSO 
{ 
    public class SharedSizeScopeViewModel : INotifyPropertyChanged 
    { 

     public SharedSizeScopeViewModel() 
     { 
      var testEntries = new ObservableCollection<TestViewModel>(); 

      testEntries.Add(new TestViewModel 
      { 
       Name = "Test", 
       Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test", 
       Name3 = "Short test", 
       Name4 = "Nothing" 


      }); 

      Entries = testEntries;   
     } 

     private ObservableCollection<TestViewModel> _entries; 

     public ObservableCollection<TestViewModel> Entries 
     { 
      get { return _entries; } 
      set 
      { 
       _entries = value; 
       OnPropertyChanged(); 
      } 
     } 


     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Prima viewmodel

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 

namespace WPFSO 
{ 
    public class SharedSizeScopeViewModel : INotifyPropertyChanged 
    { 

     public SharedSizeScopeViewModel() 
     { 
      var testEntries = new ObservableCollection<TestViewModel>(); 

      testEntries.Add(new TestViewModel 
      { 
       Name = "Test", 
       Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test", 
       Name3 = "Short test", 
       Name4 = "Nothing" 


      }); 

      Entries = testEntries;   
     } 

     private ObservableCollection<TestViewModel> _entries; 

     public ObservableCollection<TestViewModel> Entries 
     { 
      get { return _entries; } 
      set 
      { 
       _entries = value; 
       OnPropertyChanged(); 
      } 
     } 


     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Seconda viewmodel

using System.ComponentModel; 
using System.Runtime.CompilerServices; 

namespace WPFSO 
{ 
    public class TestViewModel : INotifyPropertyChanged 
    {  
     private string _name; 
     private string _name2; 
     private string _name3; 
     private string _name4; 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       _name = value; 
       OnPropertyChanged(); 
      } 
     } 

     public string Name2 
     { 
      get { return _name2; } 
      set 
      { 
       _name2 = value; 
       OnPropertyChanged(); 
      } 
     } 

     public string Name3 
     { 
      get { return _name3; } 
      set 
      { 
       _name3 = value; 
       OnPropertyChanged(); 
      } 
     } 

     public string Name4 
     { 
      get { return _name4; } 
      set 
      { 
       _name4 = value; 
       OnPropertyChanged(); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
Problemi correlati