2013-03-06 9 views
7

Moje okno WPF Windows zawiera TabControl, który wyświetla zawartość na różnych kartach. Kliknięcie poniższego przycisku wykonuje metodę przez interfejs ICommand/Binding. Wywołana metoda generuje tekst, który ma być wyświetlany w drugiej zakładce.Jak zmienić Tab z TabControl w WPF bez naruszania wzorca MVVM

Application Mockup

Jak mogę przełączyć się na drugą kartę na kliknięcia przycisku bez naruszania Wzorzec MVVM?

Próbowałem powiązać właściwość TabItem.IsSelected z czymś w moim ViewModelu, ale chciałem również użyć innych zakładek (tab1).

Jakieś myśli?

+4

Proszę nie wywoływać "okna" WPF "formularza". To zniewaga. –

+0

lol @HighCore - dosłownie powiedziałem to samo koledze kilka dni temu ... – JerKimball

+3

Proszę spojrzeć na [to] (http://stackoverflow.com/questions/15209870/dynamically-updating-tabcontrol-content- at-runtime/15210593 # 15210593) wyjaśnienie, czym jest 'TabControl' i jak powinno być traktowane, z punktu widzenia MVVM. –

Odpowiedz

11

Sam to odkryłem.

Klucz jest dwustronny. Po kliknięciu przycisku ustawia on właściwość DisplayXamlTab prawdziwa. Atrybut IsSelected jest powiązany z tą zmienną. jeśli zostanie kliknięta inna karta, powiązanie ustawi właściwość DisplayXamlTab na wartość false.

Uwaga: UpdateSourceTrigger=PropertyChanged jest również bardzo ważne

Kod pochodzi poniżej:

XAML:

 <TabItem Header="XAML" IsSelected="{Binding DisplayXamlTab, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
      <Grid Background="#FFE5E5E5"> 
       <TextBox x:Name="TxtXamlOutput" IsReadOnly="True" Text="{Binding XamlText, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> 
      </Grid> 
     </TabItem> 

C# obiektu:

private bool displayXamlTab; 
public bool DisplayXamlTab 
{ 
    get { return this.displayXamlTab; } 
    set 
    { 
     this.displayXamlTab = value; 
     this.RaisePropertyChanged("DisplayXamlTab"); 
    } 
} 
+0

W jaki sposób uzyskujesz RaisePropertyChanged? –

+0

RaisePropertyChanged jest implementacją MVVMLight interfejsu INotifyPropertyChanged. – Joel

+0

Och, zastanawiałem się nad tym - thx –

0

Najprawdopodobniej będziesz chciał użyć pewnego rodzaju wzorca "Event Aggregator" (tj. Klasy Messenger w świetle MVVM), aby nadać komunikat "nawigacyjny". Twój widok - TabControl - może nasłuchiwać określonej wiadomości i przejść do Tab2, gdy wiadomość zostanie odebrana.

Alternatywnie, możesz związać właściwość "Tabulator" z SelectedItem na swoim ViewModelu i po prostu wywołać CurrentTab = MySecondTabViewModel z wnętrza maszyny wirtualnej. Jest to approach zalecane przez @HighPoint w komentarzach do OP, ale nie jestem fanem; patrz poniżej. Innym zastrzeżeniem tego podejścia jest to, że musisz znać DataTemplates, ponieważ będziesz musiał zmapować widok do każdego wyświetlanego modelu ViewModel.

Osobiście podoba mi się pierwsze podejście, ponieważ nie uważam tego za "odpowiedzialność" ViewModel za obsługę nawigacji po kartach. Jeśli po prostu powiadomisz swój widok podczas zmiany danych w swoim ViewModelu, zezwalasz Viewowi na podjęcie decyzji, czy chce on zmienić karty.

+0

To nie jest konieczne i dodaje niepotrzebne koszty ogólne i zmniejsza łatwość konserwacji. Proszę spojrzeć na link w moim komentarzu. –

+0

@HighCore - zobacz moje komentarze powyżej. Nie jestem fanem używania wiązania "SelectedItem". – BTownTKD

+0

Nie zgadzam się. Ale masz ważny punkt. Na marginesie DataTemplates jest koniecznością dla każdego programisty WPF. Z innego, bardziej abstrakcyjnego punktu widzenia, możesz myśleć, że ustawienie "aktywnego widżetu" JEST faktycznie odpowiedzialnością VM. –

1

Można tworzyć wiązania pomiędzy modelem widok i mienia TabControl.SelectedIndex - czyli 0 wybiera pierwszą TabItem, 1 wybiera drugie itd

<TabControl DataContext="..." SelectedIndex="{Binding SomeVmProperty}" ... 

(alternatywnie, w zależności od tego, jak masz rzeczy utworzone, można powiązać przeciwko SelectedItem ...)

+2

Dlaczego to nie działa dla mnie? Zmiany właściwości, Notifys, ale interfejs użytkownika nigdy się nie zmienia. –

12

jeśli idziesz drogą MVVM masz zamiar utworzyć dwie właściwości zależnościami w kodzie za:

  • ObservableCollection<ItemType> Items;
  • ItemType MySelectedItem;

Następnie związać własność TabControl ItemsSource do Rzeczy i powiązać właściwości SelectedItem do MySelectedItem

<TabControl ItemsSource="{Binding Items}" 
     SelectedItem="{Binding MySelectedItem, Mode=TwoWay}"> 
<TabControl.ItemTemplate> 
    <DataTemplate> 
     <... here goes the UI to display ItemType ... > 
    </DataTemplate> 
    </TabControl.ItemTemplate> 
</TabControl> 

Gdy chcesz zmienić wybraną kartę, po prostu zaktualizować właściwość dependecy MySelectedItem:

2

Choć kwestia ta jest dość stary i dobrze już odpowiedziałem, myślałem, że dodam tę dodatkową odpowiedź aby pokazać alternatywny sposób zmiany wybranego TabItem w TabControl. Jeśli masz model widoku dla każdego modelu TabItem, może być pomocne posiadanie w nim właściwości IsSelected, aby określić, czy jest wybrana, czy nie. Jest możliwe, aby dane wiążą ten IsSelected nieruchomość na własność TabItem.IsSelected pomocą właściwości ItemContainerStyle:

<TabControl ItemsSource="{Binding MenuItems}" TabStripPlacement="Top"> 
    <TabControl.ItemTemplate> 
     <DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}"> 
      <StackPanel Orientation="Horizontal"> 
       <Image Source="{Binding ImageSource}" Margin="0,0,10,0" /> 
       <TextBlock Text="{Binding HeaderText}" FontSize="16" /> 
      </StackPanel> 
     </DataTemplate> 
    </TabControl.ItemTemplate> 
    <TabControl.ContentTemplate> 
     <DataTemplate DataType="{x:Type ControlViewModels:MenuItemViewModel}"> 
      <ContentControl Content="{Binding ViewModel}" /> 
     </DataTemplate> 
    </TabControl.ContentTemplate> 
    <TabControl.ItemContainerStyle> 
     <Style TargetType="{x:Type TabItem}"> 
      <Setter Property="IsSelected" Value="{Binding IsSelected}" /> 
     </Style> 
    </TabControl.ItemContainerStyle> 
</TabControl> 

Teraz można zmienić wybrany TabItem z dominującą modelu widoku jak ten:

MenuItems[0].IsSelected = true; 

Zauważ, że Ta właściwość to dane powiązane z właściwością TabItem.IsSelected, nazywając to ...:

MenuItems[1].IsSelected = true; 

... spowoduje także automatyczne ustawienie właściwości MenuItems[0].IsSelected na false. więc jeśli model widoku, z którym pracujesz, ma ustawioną właściwość IsSelected na wartość true, możesz mieć pewność, że powiązany widok zostanie wybrany w polu TabControl.

Powiązane problemy