2016-10-02 2 views
-1

Ich möchte ein TabControl erstellen, wo das TabItem würde dynamisch zur Laufzeit erstellt werden. Das TabItem sollte mit einem ViewModel verknüpft sein. Dieses Ansichtsmodell unterstützt eine Schnittstelle, die weiß, wie der Inhalt innerhalb des TabItems erstellt wird. Im Grunde genommen könnte TabItems jede Inhaltskontrolle übernehmen, die vom View-Modell zur Laufzeit entschieden wird. Ich habe verschiedene Ansätze mit TabControl.ContentTemplate oder ControlTemplate und ItemTemplate versucht, aber keiner von ihnen funktioniert. Es scheint, dass der Vorlagen-Ansatz den Typ des Inhalts innerhalb des TabItems zur Entwurfszeit kennen muss, um sich selbst rendern zu können. Die Bindungen zu einer Eigenschaft im zugeordneten Datenkontext funktionieren einwandfrei, aber die Inhaltssteuerung wird nicht angezeigt. Konnten wir nur eine neue Klasse MyTabItem: TabItem ableiten und einen benutzerdefinierten Inhalt erstellen und ihn dem Inhalt von MyTabItem zuordnen. Jeder generische Ansatz, mit dem das View-Modell den Inhalt von TabItems erstellen kann, ist erforderlich.WPF TabControl mit ViewModel aktiviert TabItem Inhaltserstellung

+0

ok .. Ich konnte meinen CustomTabItem ableiten: TabItem und dessen Inhalt im Konstruktor erstellen, indem Sie in dem View-Modell übergeben. Das ViewModel erstellt das Inhaltselement und weist es dem Inhalt von tabitem zu. Was sind die Vor- und Nachteile eines solchen Ansatzes? Ich sehe keine Antworten mit diesem Ansatz auf Stackoverflow. Es ist wie ein Standardproblem, dem ViewModel zu erlauben, den tabItems-Inhalt zu erstellen. –

Antwort

0

Können Sie einen DataTemplate für jeden Typ angeben, der dynamisch zu Ihrem TabControl hinzugefügt werden könnte? Wenn ja, würde so etwas für Sie funktionieren?

(Beachten Sie, dass die TabControl die gleichen DataTemplate sowohl für die ItemTemplate (die Vorlage des Registerkarte Header) und die ContentTemplate (die Vorlage in dem Inhalt der ausgewählten Registerkarte angezeigt zu finden). Das ist, weil wir weder angegeben haben, WPF geht einfach den Baum hinauf und findet die gleiche Vorlage für beide aus unserer Grid.Resources.Wenn Sie für jede eine andere Vorlage verwenden möchten, können Sie explizit die Vorlage für ItemTemplate angeben, wenn dies für Sie funktioniert, oder verwenden Sie eine DataTemplateSelector oder ähnlich.)

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 

    <Grid.Resources> 
     <DataTemplate DataType="{x:Type local:DescribableOne}"> 
      <Grid Background="Red"> 
       <TextBlock Text="{Binding Description}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/> 
      </Grid> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:DescribableTwo}"> 
      <Grid Background="Blue"> 
       <TextBlock Text="{Binding Description}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/> 
      </Grid> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:DescribableThree}"> 
      <Grid Background="Green"> 
       <TextBlock Text="{Binding Description}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/> 
      </Grid> 
     </DataTemplate> 
    </Grid.Resources> 

    <StackPanel Orientation="Horizontal"> 
     <Button Command="{Binding AddOne}">Add One</Button> 
     <Button Command="{Binding AddTwo}">Add Two</Button> 
     <Button Command="{Binding AddThree}">Add Three</Button> 
    </StackPanel> 

    <TabControl Grid.Row="1" ItemsSource="{Binding DynamicallyGeneratedTabs}"/> 

</Grid> 

Und die Aussicht Modell:

public class TabControlViewModel 
{ 
    public TabControlViewModel() 
    { 
     AddOne = new RelayCommand(DoAddOne); 
     AddTwo = new RelayCommand(DoAddTwo); 
     AddThree = new RelayCommand(DoAddThree); 
     DynamicallyGeneratedTabs = new ObservableCollection<IDescribable>(); 
    } 

    public ICommand AddOne { get; } 
    public ICommand AddTwo { get; } 
    public ICommand AddThree { get; } 

    public ObservableCollection<IDescribable> DynamicallyGeneratedTabs { get; } 

    private void DoAddOne() 
    { 
     DynamicallyGeneratedTabs.Add(new DescribableOne()); 
    } 

    private void DoAddTwo() 
    { 
     DynamicallyGeneratedTabs.Add(new DescribableTwo()); 
    } 

    private void DoAddThree() 
    { 
     DynamicallyGeneratedTabs.Add(new DescribableThree()); 
    } 
} 

public interface IDescribable 
{ 
    string Description { get; } 
} 

public class DescribableOne : IDescribable 
{ 
    public DescribableOne() 
    { 
     Description = "One"; 
    } 

    public string Description { get; } 
} 

public class DescribableTwo : IDescribable 
{ 
    public DescribableTwo() 
    { 
     Description = "Two"; 
    } 

    public string Description { get; } 
} 

public class DescribableThree : IDescribable 
{ 
    public DescribableThree() 
    { 
     Description = "Three"; 
    } 

    public string Description { get; } 
} 
+0

Danke @simon für die Antwort. In dem von Ihnen geposteten Beispiel kennen wir die Art des Inhalts in der Datenvorlage zur Entwurfszeit (TextBlock). Wo wie ich nicht den Typ. Um genauer zu sein, müssen meine Tab-Elemente Graphen und einige andere Untersteuerungen wie eine Tabelle anzeigen. Allerdings weiß ich nicht, wie viele Diagramme zur Entwurfszeit angezeigt werden, es hängt vom ViewModel ab. Ich möchte ein ContentControl anstelle eines TextBlocks angeben, aber ich denke, das funktioniert nicht. Beispiel: