2014-08-29 3 views
5

Ich habe ein Gitter-Steuerelement, das unter Verwendung von Stern, z.B.Wie erhalte ich WPF-Rasterspalten, die mit einem Stern definiert sind, um den Inhalt abzuschneiden?

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

jedoch ein langes TextBlock im Netz setzen, dass die Proportionen überläuft verursacht verärgert sein. z.B.

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

Dies bewirkt, dass die zentrale Spalte mehr als doppelt so groß ist wie die anderen beiden. Wie pflege ich die angegebenen Proportionen? Ist es möglich, den Inhalt zu schneiden?

Ich habe TextTrimming="CharacterEllipsis" auf die TextBlocks gesetzt, aber kein Glück.

bearbeiten

Entscheidend scheint es, das Gitter ist in einem DataTemplate, fügen Sie das folgende Verhalten zu beobachten,

<!-- 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> 

Der Grund, warum dies wichtig ist, dass ich eine andere Grid haben als ein Geschwister von ListBox, das die "Kopfzeilen" für die in der ListBox gezeigten Spalten wie folgt anzeigt:

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

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

und so ist es wichtig, dass die Spalten übereinstimmen.

Ich habe versucht, die ColumnDefinitions innerhalb des DataTemplate an den externen GridColumnDefinitions aber ich kann nicht leicht eine Bindung Verweis auf sie zu binden.

+2

Ich bin eine neue WPF-Anwendung, indem zu reproduzieren nicht in der Lage und einfügen und diese XAML im Fenster. Sind Sie sicher, dass Sie alle Ihre Vorlagen/Codes hier eingeben? Es könnte einen Stil/Auslöser/Vorlage/Animation geben, die interferieren. Versuchen Sie, das Problem minimal darzustellen. –

+0

normalerweise 'auto' width hat ein solches Problem,' * 'wird die Breite beschränken, es sei denn, es gibt eine automatische Breite in einem seiner übergeordneten Container. – pushpraj

+1

Ich habe es reproduziert und es trimmt korrekt mit 'TextTrimming = "CharacterEllipsis"' – AxdorphCoder

Antwort

5

Dies ist eines der nervigsten Probleme mit WPF. Da der verfügbare Platz, der dem Vorlagengitter zurückgegeben wird, unendlich ist, nimmt der tatsächliche Inhalt so viel Platz in Anspruch, wie er möchte.

Der einfachste Weg besteht darin, eine bestimmte Breite an das Raster anzupassen, aber das löst nur die Situationen, in denen keine Größenänderung stattfindet.

Während Sie die ListBox Größe (Breite, in der spezifischen) zu dehnen, denke ich leider, dass es keine bessere Lösung als einen benutzerdefinierten Konverter gibt.

Hier ist meine Lösung:

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

Und der Konverter:

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" 

auf dem Textblock.

Es funktioniert für mich. Wie Sie definiert haben, sollte die mittlere Spalte doppelt so groß sein wie die andere.

1

Auch wenn dies eine alte Post ist Ich füge meine Erkenntnisse, wie sie könnte für andere Leute relevant sein, die diesen Beitrag lesen. Ich hatte ein ähnliches Problem (meine * Spalten teilten die Breite nicht gleichmäßig wie erwartet auf, sie wurden nur basierend auf dem Inhalt dimensioniert). Der Grund dafür war, dass ich eine ListView mit einer ItemsSource hatte, die mit einer Liste verknüpft war. Die ListView in WPF enthält einen ScrollViewer und ein ScrollViewer hat keine feste Breite. Ohne eine feste Breite kann ein Grid nicht richtig bestimmen, welche Breite einer * Spalte zugewiesen werden soll und zu einer anderen Größenmethode wechseln.

Lösung ich jetzt ein Itemscontrol verwenden, die das Grid richtig Größe keine Scroll enthalten und somit die Breite bekannt ermöglicht es Spalten ist.

Weitere Informationen darüber, wie genau das Grid behandelt es Sizing Ich schlage vor, Sie die Grid-Klasse dekompilieren und einen Blick auf die folgende Methode haben:

protected override Size MeasureOverride(Size constraint) 

Das ist mein MainWindow.xaml aus meiner Testanwendung ist (Kommentar aus dem Listview den Unterschied im Verhalten zu sehen):

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

Erstes Ansichtsmodell

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

Second 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)); 
     } 
    } 
} 
Verwandte Themen