2009-08-13 12 views
21

Próbuję napisać prosty projekt do nauki WPF, który tworzy zestaw przycisków wewnątrz okna głównego z opcją zmiany rozmiaru. Każdy element kolekcji musi mieć jedną wartość: Button, a zawartość tej kolekcji może się różnić w czasie wykonywania. Chcę, aby przyciski wypełniały całe okno (np. 1 przycisk @ 100% szerokości, 2 przyciski @ szerokość 50%, 3 przyciski przy 33% szerokości itd. Wszystkie na 100% wysokości). Uproszczona wersja tego, co pisałem do tej pory to:Sterowanie rozciąganiem w celu uzupełnienia ItemsControl

<ItemsControl x:Name="itemscontrolButtons" ItemsSource="{Binding}"> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Button Tag="{Binding}"> 
     <TextBlock Text="{Binding}" /> 
     </Button> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    <ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
     <StackPanel Orientation="Horizontal" /> 
    </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
...  
List<string> listButtonTexts = new List<string>() { "Button1", "Button2" }; 
... 
itemscontrolButtons.DataContext = listButtonTexts; 

Wynika to w ten sposób:

alt text

nie byłem w stanie zrobić przyciski rozciągnąć, aby dopasować szerokość i moje próby użycie Grid zamiast StackPanel było bezowocne.

Następnie, jako opcjonalne ulepszenie, byłbym wdzięczny za sugestie, jak dostosować to tak, że jeśli jest tak wiele przycisków, że nie mogą one pasować poprawnie na linii lub są węższe niż próg, to zawinie się na nową linię (w ten sposób zmniejszając o połowę wysokość przycisku, jeśli przechodzisz z 1 do 2 rzędów).

Chciałbym podkreślić, że chciałbym wiedzieć, jak to zrobić WPF way. Rozumiem, że mogę spożywać komunikaty o zmianie wielkości okna i zmieniać rozmiar kontrolek jawnie, i tak bym to zrobił z MFC lub WinForm, ale z tego, co przeczytałem, nie wynika, jak takie rzeczy powinny być robione z WPF.

Odpowiedz

48

Wymień panel kontrolki elementu z UniformGrid, to wielkość wola wszystkie dzieci, więc wszystko pasuje dokładnie:

<ItemsControl> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="1"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
+0

To było właśnie to, czego potrzebowałem do mojego głównego celu, dziękuję. – Gregyski

+0

Dzięki odpowiedzi Nira udało mi się spełnić opcjonalne kryterium. Szczegóły znajdują się w odpowiedzi na to pytanie. Na Meta polecono mi, że radzę sobie z tą sytuacją w ten sposób. http://meta.stackexchange.com/questions/14306/my-improved-answer-based-on-anothers-accepted-answer-for-my-own-question – Gregyski

+0

Dzięki! Tego właśnie mi brakowało do równomiernego rozmieszczania elementów i ich panelu w skrzynce listy. –

0
<!-- width must be explicitly set for this example --> 
<StackPanel 
    Name="MyStack" 
    Orientation="Horizontal" 
    Width="250" 
    Load="Window_Loaded"> 
    <Button/> 
    <Button/> 
    <Button/> 
</StackPanel> 

public void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    UIElementCollection elements = MyStack.Children; 
    int count = elements.Count; 

    foreach (UIElement element in elements) 
    { 
     if (element is Button) 
      ((Button)element).Width = MyStack.Width/count; 
    } 
} 
+0

Edytowałem mój post tylko 20 minut przed odpowiedzią, aby wyjaśnić, że chcę uniknąć jawnego ustawienia szerokości. Przepraszam, powinienem był pomyśleć o tym początkowo. Jawne zarządzanie takimi wymiarami (oraz obsługa komunikatów o zmianie rozmiaru) może być konieczne dla mojego dodatkowego wymagania, jeśli ma być użyty WrapPanel. Dzięki. – Gregyski

2

udało mi się zbudować na odpowiedź NIR, aby spełnić moje opcjonalne kryterium umożliwiające rozciąganie zarządzane przez WPF z wieloma wierszami.

Najpierw musisz mieć możliwość zmiany właściwości szablonu UniformGrid. Aby to zrobić, musisz zapisać odniesienie do niego. Istnieje multiple methods for accomplishing this. Zdecydowałem się obsłużyć zdarzenie Załadowane dla UniformGrid i zapisać referencję w tym czasie.

<ItemsControl ItemsSource="{Binding}"> 
    <ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
     <UniformGrid Rows="1" Loaded="UniformGrid_Loaded" /> 
    </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

I w kodzie za:

UniformGrid uniformgridButtons; 
private void UniformGrid_Loaded(object sender, RoutedEventArgs e) 
{ 
    uniformgridButtons = sender as UniformGrid; 
} 

Następnie obsłużyć SizeChanged zdarzenie i ustawić parametr wiersze według dowolnych kryteriów, które chcesz.

private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    if ((uniformgridButtons != null) && (this.Width > 0)) 
    { 
    // Set row count according to your requirements 
    uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount)/this.Width)); 
    } 
} 

Więc ta pozwala WPF zarządzać rozciągania jak w odpowiedzi NIR, ale pozwala jednoznacznie dostosować liczbę wierszy.Powyższy kod daje ten wynik:

alt text

(animowane próbki here)


Aktualizacja 28.08.2009:

byłem dostosowania mój wniosek uczenia się tak, że ItemsControl był w DataTemplate w oddzielnym ResourceDictionary. Jednak zdarzeń takich jak Loaded nie można obsłużyć w zewnętrznym pliku XAML ResourceDictionary, ponieważ nie ma on kodu źródłowego (zwykle). Dlatego musiałem buforować odwołanie do UniformGrid przy użyciu innej techniki.

Zamiast tego użyłem Alan Haigh's FindItemsPanel method (10th reply). Po pierwsze, otrzymuje ItemsControl z:

<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" /> 

potem w moim ResourceDictionary, kładę ItemsControl w DataTemplate:

<DataTemplate DataType="{x:Type local:Buttons}"> 
    <ItemsControl ... 
</DataTemplate> 

Wreszcie przechowywane odniesienie do matrycy UniformGrid jako tak:

private void Window_Loaded(object sender, RoutedEventArgs e) { 
    uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons); 
    // Also call the code in Window_SizeChanged which I put in another method 
} 

Działa to tak samo jak moje poprzednie rozwiązanie, ale bez potrzeby obsługi zdarzeń w ResourceDictionary.

Powiązane problemy