Come estendere le intestazioni delle voci della scheda WPF alla larghezza del controllo padre

C’è un modo in XAML per far sì che le intestazioni delle voci della scheda si estendano attraverso la larghezza del controllo struttura a tabs?

Ad esempio, ho tre tabs: rosso, blu e verde. Se ho un controllo struttura a tabs con la sua larghezza impostata su auto, le intestazioni delle tabs riempiranno solo una parte dello spazio sopra il contenuto della scheda, ma voglio che riempiano tutto lo spazio. Per il mio esempio di tre tabs, il rosso dovrebbe occupare il primo terzo del controllo, il blu dovrebbe occupare il terzo centro e il verde il terzo finale.

Ho un’idea di come farlo in un codice dietro al quale sto lavorando ora, ma sono interessato a farlo nel modo più semplice ansible.

Ho preso l’esempio di Jordan e ho apportato alcune modifiche ad esso. Questa versione dovrebbe funzionare per qualsiasi numero di tabs:

namespace WpfApplication1.Converters { public class TabSizeConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { TabControl tabControl = values[0] as TabControl; double width = tabControl.ActualWidth / tabControl.Items.Count; //Subtract 1, otherwise we could overflow to two rows. return (width <= 1) ? 0 : (width - 1); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } } } 

Stesso spazio dei nomi in xaml:

 xmlns:local="clr-namespace:WpfApplication1.Converters" 

E questo farà sì che tutte le tabs lo usino:

     

Sembra che tutti UniformGrid seguendo il percorso del convertitore, ma è davvero semplice come utilizzare un UniformGrid con le Rows impostate su 1 nel modello TabControl , al posto del TabPanel . Ovviamente, dovrai ri-stamparlo, ma non è male.

Sono stato in grado di farlo usando un convertitore in questo modo:

 namespace WpfApplication1.Converters { public class SizeConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double width = Double.Parse(value.ToString()); //Subtract 1, otherwise we could overflow to two rows. return .25 * width - 1; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } #endregion } } 

Quindi aggiungendo lo spazio dei nomi al mio xaml:

 xmlns:local="clr-namespace:WpfApplication1.Converters" 

Quindi, facendo in modo che tutti i TabItem utilizzino il convertitore:

     

x_Grid è la x: Nome dell’elemento genitore Voglio che le tabulazioni siano 1/4 di, se questo ha senso.

È ansible associando la larghezza a ActualWidth del controllo di tabulazione genitore come mostrato di seguito.

L’ho avvolto in uno stile da applicare a tutte le tabs.

           

Sono un ragazzo in stile vecchia scuola. e preferisco questo tipo di funzionalità per incapsulare nel codice del controllo stesso. Il mio controllo derivato ha il seguente aspetto:

  public class CustomTabControl :TabControl { protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo) { foreach (TabItem item in this.Items) { double newW = (this.ActualWidth / Items.Count) - 1; if (newW < 0) newW = 0; item.Width = newW; } } } 

e il mio XAML sembra

     

Qualcuno può spiegare perché tutti preferiscono il controllo dello stile invece di derivare.

Ho risolto questo problema creando un convertitore speciale:

  public class TabItemWidthAdjustmentConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { Double lTabControlWidth = value is Double ? (Double)value : 50; // 50 just to see something, in case of error Int32 lTabsCount = (parameter != null && parameter is String) ? Int32.Parse((String)parameter) : 1; return lTabControlWidth / lTabsCount; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 

E calcolo il valore di una voce di tabulazione nell’elemento Tag di TabControl, per evitare di calcolarlo separatamente per ciascuna scheda. Ecco il codice di esempio (nota che nel mio caso avevo bisogno di un ScrollViewer orizzontale, perché ho più elementi di tabulazione e con una larghezza minima):

                        

Posso dire che questo funziona come un incantesimo nel mio caso 🙂 Spero che qualcuno lo trovi utile!

PS Non ho bisogno / voglio uno stile nel mio caso.

Ecco una soluzione indolore che utilizza solo modelli:

                                                                     

Spero di aver incluso tutti i colors e che funzionerà per te. Ahh … Snap! Il mio effetto di desaturazione! Il mio progetto di avvio WPF è ansible prendere questo effetto da lì, se lo desideri (è più facile plopare l’effetto nel trigger, piuttosto che ricolorare tutto, lo stesso con i punti salienti). Sì, è un sacco di codice, ma ho semplicemente cambiato ItemsContainer per avere un aspetto migliore e ho sostituito il controllo Header standard con UniformGrid e impostato Rows o Columns su 1 a seconda di TabStripPlacement. Ora posso comprimere questo codice o nasconderlo da qualche parte. 🙂

Ho seguito il suggerimento di Charlie e ho continuato a ri-templare il percorso. Ecco una semplice implementazione di TabControl che divide equamente lo spazio disponibile tra i suoi TabItem , usando UniformGrid :

Controllo XAML

                                                              

Codice di controllo: dietro

 using System.Windows.Controls; using System.Windows.Controls.Primitives; namespace YourNamespace.Views { ///  /// A TabControl with large tabs. ///  public partial class BigTabsTabControl : TabControl { public BigTabsTabControl() { InitializeComponent(); } public override void OnApplyTemplate() { base.OnApplyTemplate(); if (this.Template != null) { UniformGrid X = this.Template.FindName("headerPanel", this) as UniformGrid; if (X != null) X.Columns = this.Items.Count; } } } } 

Questo è tutto. Ora puoi aggiungere TabItem a questo controllo e TabItem automaticamente la loro larghezza. Non c’è bisogno di specificare Grid.Column per questi TabItem , funzionano senza di esso, anche in fase di progettazione.

Non so se funzionerà per le tabs, ma ogni volta che ho bisogno di allungare qualcosa per riempire un contenitore ho usato un ViewBox . È questo il tipo di cosa che stai cercando?

Oltre alla soluzione accura- ta di Ryan Versaw, che fornisce ampiezze di intestazione tabItem uguali, ho trovato il modo seguente per renderlo dipendente dalla lunghezza di ogni intestazione.

Per prima cosa otteniamo la stringa di ogni intestazione tabItem aggiungendo questa linea alla multibinding xaml. Così diventa:

      

E un po ‘più di codice nel convertitore (valori [] ottiene anche l’intestazione tabItem):

 public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { TabControl tabControl = values[0] as TabControl; string AllHeaders = ""; for (int i = 0; i < tabControl.Items.Count; i++) { int index = tabControl.Items[i].ToString().IndexOf("Header:") + "Header:".Length; string currentHeader = tabControl.Items[i].ToString().Substring(index); currentHeader = currentHeader.Substring(0, currentHeader.Length - " Content:".Length); AllHeaders += currentHeader; } //Normalize width according to header length double width = values[2].ToString().Length * tabControl.ActualWidth / AllHeaders.Length; //Subtract 1, otherwise we could overflow to two rows. var retVal = (width <= 1) ? 0 : (width - 1); return retVal; } 

Sospetto che ci possa essere un modo più efficiente per ottenere la stringa AllHeaders di tutte le intestazioni, ma funziona bene così com'è ...

Sto usando la seguente soluzione: Nella finestra principale io uso un evento ridimensionato della finestra e sul tabcontrol Evento inizializzato per impostare la larghezza di ogni tabulazione. Il numero ‘5’ corrisponde al mio numero di tabs.

  private void tabchanger_Initialized(object sender, EventArgs e) { foreach (TabItem item in tabchanger.Items) { double newW = (tabchanger.ActualWidth / 5) - 1; if (newW < 0) newW = 0; item.Width = newW; } } private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { foreach (TabItem item in tabchanger.Items) { double newW = (tabchanger.ActualWidth / 5) - 1; if (newW < 0) newW = 0; item.Width = newW; } }