2015-03-11 10 views
5

Czy można dostosować szerokość wszystkich bloków TextBlock w WrapPanel do rozmiaru największej blokady TextBlock w WrapPanel? Końcowym rezultatem powinno być to, że szerokość kontrolki zawierającej "Niektóre dane" ma taką samą szerokość jak kontrolka zawierająca "Jeszcze więcej danych niż wcześniej". Dołączyłem do mojego początkowego kodu jako punkt wyjścia. Użyłem ciągów jako przykładu, ale dane i szablon kolekcji mogą być dowolne, więc nie mogę polegać na długości ciągu znaków.WPF: Synchronizuj szerokość wszystkich elementów w ItemsControl

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:System="clr-namespace:System;assembly=mscorlib" 
     xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <Collections:ArrayList x:Key="data"> 
      <System:String>Some data</System:String> 
      <System:String>Some more data</System:String> 
      <System:String>Even more data than before</System:String> 
     </Collections:ArrayList> 
    </Window.Resources> 
    <ItemsControl ItemsSource="{StaticResource data}"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel></WrapPanel> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Border Margin="5" BorderThickness="1" BorderBrush="Black"> 
        <TextBlock Text="{Binding}"></TextBlock> 
       </Border> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Window> 

A obraz pożądanego wyjścia:

Desired output

Odpowiedz

10

Użyj wspólną siatkę rozmiar:

<ItemsControl ItemsSource="{StaticResource data}" Grid.IsSharedSizeScope="True"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel></WrapPanel> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto" SharedSizeGroup="ColumnSize" /> 
       </Grid.ColumnDefinitions> 
       <Border Margin="5" BorderThickness="1" BorderBrush="Black"> 
        <TextBlock Text="{Binding}"></TextBlock> 
       </Border> 
      </Grid> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 

Wszystkie kolumny są gwarancją taką samą szerokość jak dzielą grupę size. Ponieważ są one rozmiaru auto, będą również rozmiaru do największego wystąpienia dowolnej zawartości siatki.

+0

Całkiem eleganckie rozwiązanie. To rozwiązuje mój natychmiastowy problem całkiem ładnie, bez konieczności pisania niestandardowego kodu. Czy są jakieś ograniczenia, które natychmiast przychodzą ci na myśl w tej odpowiedzi? – mortalapeman

4

Musisz utworzyć własną niestandardową wersję wrappanel że pochodzi od wrappanel aby osiągnąć to, co chcesz. Normalnie na panelu niestandardowego trzeba nadpisać następujące 2 metody:

  • MeasureOverride
  • ArrangeOverride

W twoim przypadku trzeba measueoverride gdzie można iteracyjne nad elementami i dowiedzieć się, który z nich jest największy, a następnie użyj tego samego rozmiaru dla wszystkich elementów w aranżacji overover.

trochę więcej informacji na temat tworzenia panel niestandardowe: http://www.wpftutorial.net/CustomLayoutPanel.html

+0

Niestandardowy panel z lekko zmodyfikowanymi właściwościami panelu zawijania był tym, na co myślałem, że będę musiał się zadowolić, ale tak jest, dopóki nie zobaczyłem odpowiedzi @TobyCrawford. – mortalapeman

2

Możesz dodać HorizontalContentAlignment = Stretch i dodać UniformGrid w itemsPanel.

<Window.Resources> 
    <Collections:ArrayList x:Key="data"> 
     <System:String>Some data</System:String> 
     <System:String>Some more data</System:String> 
     <System:String>Even more data than before</System:String> 
    </Collections:ArrayList> 
</Window.Resources> 
<ListBox ItemsSource="{StaticResource data}" HorizontalContentAlignment="Stretch"> 
    <ListBox.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid IsItemsHost="True"></UniformGrid> 
     </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Border Margin="5" BorderThickness="1" BorderBrush="Black" > 
       <TextBlock Text="{Binding}" Width="{Binding 
      RelativeSource={RelativeSource TemplatedParent}, 
      Path=Width}"></TextBlock> 
      </Border> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 
+0

UniformGrid, rozwiązanie większych problemów niż można się spodziewać. – Will

+0

IMHO nie spełnia wymagań PO. Co się stanie, jeśli zmieni rozmiar okna? –

+0

Nie wiedziałem o UniformGrid do tego postu, dziękuję za to. Niestety, muszę zgodzić się z @PhilipStuyck w tym, że nie ma tej samej właściwości zmiany rozmiaru panelu wrap. – mortalapeman

1

Jest to alternatywa dla niestandardowej sugestii panelu Philipa Stuycka, która może być bardziej zrozumiała dla danego scenariusza. (Jest to wprawdzie trochę hack.)

Możesz obliczyć długość struny, używając klasy FormattedText. Możesz więc powtórzyć ciągi i obliczyć maksymalną długość (zakłada to również, że znasz rodzinę i rozmiar czcionki). Następnie ogranicz szerokość bloków tekstu do maksymalnej szerokości. Chciałbym zapisać wartość szerokości w jednym własności na poziomie macierzystym, a następnie za pomocą RelativeSource wiązania:

<TextBlock Text="{Binding}" 
      Width="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, 
          Path=MaximumWidth}}" 
     /> 

(Wadą tego podejścia jest to, że w przypadku zmiany pozycji zbiórki, musisz przeliczyć MaximumWidth.)

+0

Niestety, nie mogę obliczyć długości napisu, ponieważ mój prawdziwy problem nie ma nic wspólnego ze stringami, używałam ich tylko jako przykładu. Zastanawiałem się nad powiązaniem szerokości przodków, ale liczyłem na bardziej eleganckie rozwiązanie. Jednak nadal dobrze jest wiedzieć, że można to zrobić w ten sposób. – mortalapeman

Powiązane problemy