2009-08-13 13 views
21

Sto tentando di scrivere un semplice progetto di apprendimento WPF che crea un insieme di pulsanti all'interno di una finestra principale ridimensionabile. Ci deve essere uno Button per voce in una raccolta e il contenuto di tale raccolta può variare durante l'esecuzione. Voglio che i pulsanti riempiano l'intera finestra (ad esempio 1 pulsante @ larghezza 100%, 2 pulsanti @ larghezza 50%, 3 pulsanti @ larghezza 33%, ecc. Tutti all'altezza 100%). Una versione semplificata di quello che ho scritto finora è:Estendere i controlli per riempire 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; 

Questo si traduce in questo:

alt text

sono stato in grado di rendere i pulsanti si estendono in base alla larghezza ed i miei tentativi utilizzare un Grid invece di StackPanel era inutile.

Quindi, come miglioramento opzionale, gradirei suggerimenti su come regolarlo in modo tale che se ci sono così tanti pulsanti che non possono adattarsi correttamente su una linea o sono più stretti di una soglia, si avvolgerà su una nuova linea (quindi dimezzare le altezze dei pulsanti se si passa da 1 a 2 righe).

Mi piacerebbe sottolineare che mi piacerebbe sapere come fare questo il modo WPF. Mi rendo conto che posso consumare i messaggi di ridimensionamento delle finestre e ridimensionare i controlli in modo esplicito, ed è così che l'avrei fatto con MFC o WinForms, ma da quello che ho letto non è il modo in cui tali cose dovrebbero essere fatte con WPF.

risposta

48

Sostituire il pannello di controllo di voce con un UniformGrid, questa dimensione volontà tutti i bambini quindi tutto si adatta esattamente:

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

Era proprio quello di cui avevo bisogno per il mio obiettivo principale, grazie. – Gregyski

+0

Grazie alla risposta di Nir, sono riuscito a soddisfare il criterio facoltativo. I dettagli sono nella risposta che ho inviato a questa domanda. Mi è stato consigliato su Meta di gestire questa situazione in questo modo. http://meta.stackexchange.com/questions/14306/my-improved-answer-based-on-anothers-accepted-answer-for-my-own-question – Gregyski

+0

Grazie! Questo è proprio quello che mi mancava per spaziatura degli oggetti e il loro pannello in modo uniforme in una lista. –

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

Ho modificato il mio post solo 20 minuti prima di rispondere per spiegare che volevo evitare di impostare esplicitamente la larghezza. Mi dispiace che avrei dovuto pensare di includere inizialmente quel requisito. La gestione esplicita delle dimensioni come questa (e anche gestendo i messaggi di ridimensionamento) potrebbe essere necessaria per il mio requisito secondario, se WrapPanel dovesse essere utilizzato. Grazie. – Gregyski

2

sono stato in grado di costruire su risposta di Nir per compiere la mia criterio opzionale che consente lo stiramento gestito da WPF con più righe.

Per prima cosa è necessario modificare le proprietà del modello UniformGrid. Per fare ciò è necessario memorizzare un riferimento ad esso. Ci sono multiple methods for accomplishing this. Ho scelto di gestire l'evento Loaded per UniformGrid e memorizzare un riferimento in quel momento.

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

E nel codice dietro:

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

Poi, gestire il SizeChanged evento e regolare il parametro di file in base a qualsiasi criterio che si desidera.

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

Quindi questo permette WPF per gestire l'allungamento come nella risposta di Nir, ma consente di regolare in modo esplicito il numero di righe.Il codice di cui sopra dà questo risultato:

alt text

(Animated campione here)


Aggiornamento 2009/08/28:

mi stava sistemando la mia domanda di apprendimento in modo che il ItemsControl era in un DataTemplate in un separato ResourceDictionary. Tuttavia, eventi come Loaded non possono essere gestiti in un file XAML esterno ResourceDictionary perché non ha code-behind (di solito). Pertanto, avevo bisogno di memorizzare nella cache il riferimento allo UniformGrid utilizzando una tecnica diversa.

Ho invece utilizzato Alan Haigh's FindItemsPanel method (10th reply). In primo luogo, ho sostituito il ItemsControl con:

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

Poi nel mio ResourceDictionary, ho messo il ItemsControl nella DataTemplate:

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

Infine, ho conservato il riferimento al template UniformGrid come così:

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 
} 

Questo funziona esattamente come la mia soluzione precedente ma senza richiedere un gestore di eventi nel ResourceDictionary.

Problemi correlati