0

On my way exploring/studying WPF/MVVM I have been assisted at least twice in this community with good results. Thanks fort that and I’m back again. On advice of Blinksy and Clemens I did implement dynamic TabItem construction based on a ObservableCollection. So far so good. Now I’m trying to figure out how to Bind each TabItem to it’s corresponding class instance in the OneViewModel. Have been searching for an Event like TabControl_SelectionChanged to find (and set) a relation between the selected TabItem and the corresponding MyTabItem class in OneViewModel. But no success until know. High time to ask this community for an idiomatic way to accomplish this.

<Window x:Class="FourTabsOneView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vws="clr-namespace:FourTabsOneView.Views"
        xmlns:vms="clr-namespace:FourTabsOneView.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">

    <Window.DataContext>
        <vms:OneViewModel />
    </Window.DataContext>
    
    <TabControl x:Name="tControl" SelectionChanged="tControl_SelectionChanged" ItemsSource="{Binding MyTabItems}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Header}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <vws:OneView></vws:OneView> 
            </DataTemplate>
        </TabControl.ContentTemplate>            
    </TabControl>
</Window>

namespace FourTabsOneView;
public partial class MainWindow : Window
{
    public MainWindow()
    {
        Debug.WriteLine("MainWindow ctor");
        InitializeComponent();
    }

    private void tControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TabControl tc = (TabControl)sender;
        int x = ((TabControl)sender).SelectedIndex;
        Debug.WriteLine($"index={x}");
    }
}

<UserControl x:Class="FourTabsOneView.Views.OneView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:vms="clr-namespace:FourTabsOneView.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="200" d:DesignWidth="400">
    <UserControl.DataContext>
        <vms:OneViewModel />
    </UserControl.DataContext>
    <StackPanel Orientation="Vertical">
        <CheckBox x:Name="cb01" IsThreeState="False" Height="30" 
                          IsChecked="{Binding CB01}"
                          Content="CheckBox A" />
        <CheckBox x:Name="cb02" IsThreeState="False" Height="30"
                          IsChecked="{Binding CB02}"
                          Content="CheckBox B" />
        <CheckBox x:Name="cb03" IsThreeState="False" Height="30"
                          IsChecked="{Binding CB03}"
                          Content="CheckBox C" />
        <CheckBox x:Name="cb04" IsThreeState="False" Height="30"
                          IsChecked="{Binding CB04}"
                          Content="CheckBox D" />
    </StackPanel>
</UserControl>

namespace FourTabsOneView.Views;
public partial class OneView : UserControl
{
    public OneView()
    {
        Debug.WriteLine("OneView ctor");
        InitializeComponent();
    }
}


    namespace FourTabsOneView.ViewModels;
    internal class OneViewModel : ViewModelBase
    {
        public ObservableCollection<MyTabItem> MyTabItems { get; set; }    
    
        public OneViewModel()
        {
            Debug.WriteLine("OneViewModel ctor");
            MyTabItems = new ObservableCollection<MyTabItem>
            {
                new MyTabItem { ID = 1, Header = "TabOne" },
                new MyTabItem { ID = 2, Header = "TabTwo" },
                new MyTabItem { ID = 3, Header = "TabThree" },
                new MyTabItem { ID = 4, Header = "TabFour" }
            };
        }
    
        public sealed class MyTabItem : ViewModelBase
        {
            public int ID { get; set; }
            public string? Header { get; set; }
    
            private bool cb01_checked;
            public bool CB01
            {
                get
                {
                    return cb01_checked;
                }
                set
                {
                    cb01_checked = value;
                    OnPropertyChanged(nameof(CB01));
                }
            }
    
            private bool cb02_checked;
            public bool CB02
            {
                get
                {
                    return cb02_checked;
                }
                set
                {
                    cb02_checked = value;
                    OnPropertyChanged(nameof(CB02));
                }
            }
    
            private bool cb03_checked;
            public bool CB03
            {
                get
                {
                    return cb03_checked;
                }
                set
                {
                    cb03_checked = value;
                    OnPropertyChanged(nameof(CB03));
                }
            }
    
            private bool cb04_checked;
            public bool CB04
            {
                get
                {
                    return cb04_checked;
                }
                set
                {
                    cb04_checked = value;
                    OnPropertyChanged(nameof(CB04));
                }
            }
        }
    }
  • The UserControl must not set its own DataContext, because that breaks the default value inheritance of the property. Remove the DataContext assignment from the control's XAML. – Clemens Jul 27 '23 at 07:28
  • As a note, the MyTabItems property should be read-only: `public ObservableCollection MyTabItems { get; }`. If it had a public setter, it would have to fire a change notification. – Clemens Jul 27 '23 at 07:32
  • @Clemens Vielen Dank! Ich setze meinen Spaziergang im WPF Wald, mit dem MVVM Gebüsch, fort. – Aad Slingerland Jul 27 '23 at 17:18

0 Answers0