2009-10-19 14 views
16

E 'possibile mettere un TabItem in XAML e riferimento qualcosa di separato in questo modo:TabItem in XAML separata

<TabControl> 
    <local:MyTabItem/> 
</TabControl> 



In Separate XAML: 
<UserControl x:Class="MyProject.MyTabItem" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <TabItem Header="MyTab"> 

    </TabItem> 
</UserControl> 

Naturalmente non funziona, ma mi chiedo come posso fare questo?

risposta

31

Se ciò che si vuole fare è semplicemente rendere il codice più gestibile allora mi sento di raccomandare di definire i dati di ciascuna scheda in un controllo utente, ma ho ancora il TabItem nel controllo tab principale.

Supponiamo che il codice originale era questa:

<TabControl> 
    <TabItem Header="Tab 1"> 
     <Grid> 
      <TextBlock Text="Tab Data" /> 
     </Grid> 
    </TabItem> 
</TabControl> 

Per rendere il codice più gestibile si potrebbe rompere il contenuto della scheda in un UserControl come ad esempio:

<UserControl x:Class="WpfApplication19.Tab1Data" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      > 
    <Grid> 
     <TextBlock Text="Tab Data" /> 
    </Grid> 
</UserControl> 

e quindi utilizzare tale utente controllo nel TabControl in questo modo:

<TabControl> 
     <TabItem Header="Tab 1"> 
      <tabData:Tab1Data /> 
     </TabItem> 
    </TabControl> 

Se si desidera includere e TabItem nel controllo utente, quindi è possibile farlo creando prima un controllo utente e quindi modificare il tipo del controllo utente sul tipo TabItem (assicurarsi di modificarlo sia nel nodo radice xaml che nel codice sottostante).

Questo sarebbe lasciare con un controllo della linguetta che assomiglia a questo:

<TabControl> 
     <tabData:TabItem1 /> 
     <tabData:TabItem2 /> 
     <tabData:TabItem3 /> 
    </TabControl> 

E ogni TabItem1 'di controllo utente' sarebbe di tipo TabItem. Ecco un esempio:

<TabItem x:Class="WpfApplication19.TabItem1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Header="Tab 1" 
     > 
    <Grid> 
     <TextBlock Text="Tab Data" /> 
    </Grid> 
</TabItem> 

E come ho già detto, assicurarsi di modificare il codice dietro in modo che TabItem estende al posto di controllo utente:

public partial class TabItem1 : TabItem 
{ 
    public TabItem1() 
    { 
     InitializeComponent(); 
    } 
} 
+0

Grazie mille. Funziona perfettamente come hai mostrato nella tua risposta! –

+12

tabdata proviene da dove? –

+0

Come hai ottenuto che la proprietà 'xmlns' funzioni come hai mostrato? Per quanto ne so, richiede di essere in un'assemblea straniera. –

2

Sulla superficie sembra che sarebbe meglio risolvere uno stile e/o un modello per il controllo TabItem che è possibile memorizzare in un file di risorse separato. Quanto è necessario personalizzare l'effettivo TabItem determinerà se è possibile utilizzare solo uno stile o se è necessario un modello.

Che cosa si può fare è definire uno stile di nome per ogni TabItem in un file di risorse separato in questo modo, creare un MyResources.xaml che sembra qualcosa di simile:

<ResourceDictionary> 
    <Style x:Key="MyTabItem" TargetType="{x:Type TabItem}"> 
     <!-- 
      you can just use simple property setters to set up 
      the TabItem or set the Template property to replace 
      entire tab look and feel 
     --> 
    </Style> 
</ResourceDictionary> 

Poi nel file App.xaml principale si uniscono nel dizionario risorse:

<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="MyResources.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

Infine nella vostra applicazione che si sarebbe sfruttare questi stili semplicemente facendo:

<TabItem Style="{DynamicResource MyTabItem}" /> 
+0

Scusate, avrei dovuto elaborarlo di più. Non ho intenzione di riutilizzare, ma rendere il mio codice più gestibile. In questo momento ho tutto il mio XAML nella mia finestra principale. Gli articoli più voluminosi sono contenuti in un TabControl. Rompere i TabItem che contengono diversi controlli, renderebbe molto più facile da gestire. Sono solo un principiante, quindi non so quale sia l'approccio migliore. Cercherò di creare un modello per TabItem. –

+1

Ok, allora penso ancora che l'approccio stile/modello che ho suggerito sia una buona soluzione per questo. Elaborerò nella mia risposta. –

+0

-1 John Sheares stava chiedendo un modo per dividere i file XAML, non ridurre il codice ridondante. –

1

Penso che quello che volevi è quello di ottenere TabItem Il contenuto dichiara separatamente. Poiché TabItem è un ContentControl, puoi presentare un UserControl come suo contenuto.

<TabControl> 
    <TabItem> 
     <local:YourTabContent1/> 
    </TabItem> 
    <TabItem> 
     <local:YourTabContent2/> 
    </TabItem> 
</TabControl> 

In XAML separato:

<UserControl x:Class="MyProject.YourTabContent1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <......blah blah.../> 
</UserControl> 

In un altro XAML si può avere contenuti 2

<UserControl x:Class="MyProject.YourTabContent2" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <......blah blah.../> 
</UserControl> 
+0

Anche questo funziona. Una cosa che ho notato è che devo ridefinire nuovamente le mie risorse all'interno del contenuto della scheda XAML perché quelle definite per la finestra non sono disponibili. Inoltre, come posso ottenere un controllo che si trova in una delle schede dalla finestra code-behind che contiene TabControl? Uso FindName()? –

11

La risposta precedente da Tony Borres copre già gli aspetti più importanti. Ma l'ulteriore commento richiede l'accesso dal codice sottostante. Quindi estenderò l'esempio da Tony per mostrare anche questo aspetto. Questa risposta mostra gli spazi dei nomi richiesti. Li ho aggiunti anche alla risposta di Tony.

Per semplificare la gestione del codice, si consiglia di definire i dati di ciascuna scheda in un controllo utente, ma di avere ancora il TabItem nel controllo della scheda principale. Questa strategia è utile ad esempio per aggirare FxCop CA1505: "Evita il codice non gestibile" quando si utilizza un controllo struttura a schede con più voci di tabulazione.

Supponiamo che questo è il codice originale:

<Window x:Class="WpfApplication19.MainWindow" ...> 
    <TabControl> 
     <TabItem Header="Tab 1"> 
      <Grid> 
       <TextBlock Text="Data on Tab 1" Name="txtData1" /> 
      </Grid> 
     </TabItem> 
     <TabItem Header="Tab 2"> 
      <Grid> 
       <TextBlock Text="Data on Tab 2" Name="txtData2" /> 
      </Grid> 
     </TabItem> 
    </TabControl> 
</Window> 

Per rendere il codice più gestibile il contenuto della scheda possono essere spostati in un UserControl come ad esempio:

<UserControl x:Class="WpfApplication19.Tab1Data" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      Loaded="OnControlLoaded" 
      > 
    <Grid> 
     <TextBlock Text="Data on Tab 1" Name="txtData1" /> 
    </Grid> 
</UserControl> 

E poi è possibile utilizzare il nuovo controllo utente nel TabControl in questo modo:

<Window x:Class="WpfApplication19.MainWindow" 
     xmlns:tabData="clr-namespace:WpfApplication19" ...> 
    <TabControl> 
     <TabItem Header="Tab 1"> 
      <tabData:Tab1Data x:Name="ucTab1Data" /> 
     </TabItem> 
     <TabItem Header="Tab 2"> 
      <Grid> 
       <TextBlock Text="Data on Tab 2" Name="txtData2"/> 
      </Grid> 
     </TabItem> 
    </TabControl> 
</Window> 

Ora possibile per accedere ai wigdets interni del controllo utente dalla finestra principale e viceversa. Si prega di notare "x:" davanti al nome del controllo utente.

public partial class MainWindow : Window 
{ 
    private void AccessWidgetWithinUserControl() 
    { 
     ucTab1Data.txtData1.Text = "New text on Tab 1"; 
    } 
} 

public partial class Tab1Data : UserControl 
{ 
    private MainWindow mainWindow = null; // Reference to the MainWindow 

    public Tab1Data() 
    { 
     InitializeComponent(); 
    } 

    // get a reference to main windows when it is available. 
    // The Loaded Event is set in the XAML code above. 
    private void OnControlLoaded(object sender, RoutedEventArgs e) 
    { 
     mainWindow = Window.GetWindow(this) as MainWindow; 
    } 

    private void AccessMainWindowsWidget() 
    { 
     mainWindow.txtData2.Text = "New text on Tab 2 in the main window"; 
    } 
} 

Il codice visualizzato per accedere a txtData2 sarebbe lo stesso anche se è incorporato nel proprio controllo utente.