WPF tab control and MVVM selection

前端 未结 4 1373
遥遥无期
遥遥无期 2020-12-29 04:44

I have a TabControl in an MVVM WPF application. It is defined as follows.



        
相关标签:
4条回答
  • 2020-12-29 05:16

    Just FYI, I gone through the same issue where I add tabs dynamically using ObservableCollection source but last added Tab do not get selected. I have done same changes what Sheridan said to select Tab as per SelectedIndex. Now last added Tab gets selected but it was not getting focused. So to focus the Tab we have to add set Binding IsAsync property True.

    <TabControl ItemsSource="{Binding Workspaces}" Margin="5" SelectedIndex="{Binding TabIndex, Mode=OneWay,UpdateSourceTrigger=PropertyChanged, IsAsync=True}">
    
    0 讨论(0)
  • 2020-12-29 05:20

    The below code sample will create a dynamic tab using MVVM.

    XAML

    <TabControl Margin="20" x:Name="tabCategory"
                    ItemsSource="{Binding tabCategory}"
                    SelectedItem="{Binding SelectedCategory}">
    
        <TabControl.ItemTemplate>
            <DataTemplate>
                <HeaderedContentControl Header="{Binding TabHeader}"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
    
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding TabContent}" />
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
    

    Modal Class

    TabCategoryItem represents each tab item. On two properties, TabHeader will display a tab caption and TabContent contains the content/control to fill in each tab.

    Public Class TabCategoryItem
    
        Public Property TabHeader As String
        Public Property TabContent As UIElement
    End Class
    

    VM Class

    Public Class vmClass
    
        Public Property tabCategory As ObjectModel.ObservableCollection(Of TabCategoryItem)
        Public Property SelectedCategory As TabCategoryItem
    End Class
    

    The below code will fill and bind the content. I am creating two tabs, tab1 and tab2. Both tabs will contain text boxes. You can use any UIelement instead of text boxes.

    Dim vm As New vmClass
    
    vm.tabCategory = New ObjectModel.ObservableCollection(Of TabCategoryItem)
    
    'VM.tabCategory colection will create all tabs
    
    vm.tabCategory.Add(New TabCategoryItem() With {.TabHeader = "Tab1", .TabContent = new TextBlock().Text = "My first Tab control1"})
    vm.tabCategory.Add(New TabCategoryItem() With {.TabHeader = "Tab2", .TabContent = new TextBlock().Text = "My first Tab control2"})
    
    mywindow.DataContent = vm
    
    0 讨论(0)
  • 2020-12-29 05:31

    The accepted answer is not working with DependencyObject on your ViewModel .

    I'm using MVVM with DependencyObject and Just setting the TabControl didn't work for me.The problem I had was the the property was not getting update on the View when I was setting the tab selectedIndex from the ViewModel.

    I did set the Mode to be two ways but nothing was working.

    <TabControl  SelectedIndex="{Binding SelectedTab,Mode=TwoWay}" >
        ...
    </TabControl>
    

    The ViewModel property "SelectedTab" was getting updated all the time when I navigated between tabs. This was confirming my binding was working properly. Each time I would navigate the tabs both the Get and Set would get called in my ViewModel. But if I try to set the SelectedIndex in the ViewModel it would not update the view. ie: SelectedTab=0 or SelectedTab=1 etc... When doing the set from the ViewModel the SelectedTab 'set' method would be called, but the view would never do the 'get'.

    All I could find online was example using INotifyPropertyChanged but I do not wish to use that with my ViewModel.

    I found the solutions in this page: http://blog.lexique-du-net.com/index.php?post/2010/02/24/DependencyProperties-or-INotifyPropertyChanged

    With DependencyObject, you need to register the DependencyProperties. Not for all properties but I guess for a tabcontrol property you need to.

    Below my code:

    view.xaml

    //Not sure below if I need to mention the TwoWay mode
    <TabControl  SelectedIndex="{Binding SelectedTab,Mode=TwoWay}" >
            ...
    </TabControl>
    

    ViewModel.cs

    public class ViewModel : DependencyObject
    {
           public static readonly DependencyProperty SelectedTabDP =  DependencyProperty.Register("SelectedTab", typeof(int), typeof(ViewModel));
    
           public int SelectedTab
           {
              get { return (int)GetValue(SelectedTabDP); }
              set { SetValue(SelectedTabDP, value); }
           }
    }
    

    Basically all I had to do was to actually register the dependency property (DependencyProperty) as you can see above.

    What made this hard to figure out was that I have a bunch of other Properties on that view and I didn't need to register them like that to make it work two ways. For some reason on the TabControl I had to register the property like I did above.

    Hope this help someone else.

    Turns out my problem were because my components have names:

    x:Name="xxxxxxxx"
    

    Giving names to components at the same time of biding them with DependencyObject seems to be the main cause of all my issues.

    0 讨论(0)
  • 2020-12-29 05:34

    If you look at the TabControl Class page on MSDN, you'll find a property called SelectedIndex which is an int. Therefore, simply add an int property into your view model and Bind it to the TabControl.SelectedIndex property and then you can select whichever tab you like at any time from the view model:

    <TabControl SelectedIndex="{Binding SelectedIndex}">
        ...
    </TabControl>
    

    UPDATE >>>

    Setting a 'startup' tab is even easier using this method:

    In view model:

    private int selectedIndex = 2; // Set the field to whichever tab you want to start on
    
    public int SelectedIndex { get; set; } // Implement INotifyPropertyChanged here
    
    0 讨论(0)
提交回复
热议问题