I still think that UserControl is a View that contains a part of the view, it should have minimal logic.
Let's try to implement something like that. I personally will do with the possibility of expansion and for this I use the interface. Its role is simple, to contain the tab header:
public interface ITabViewModel { string Header { get; set; } }
Next we need some kind of ViewModel, which will contain the implementation of a specific tab. In my example, it will contain the title, color, text, and color update method:
public class ViewModelA: VM, ITabViewModel { public string Header { get; set; } public string Text { get; set; } private Brush _color; public Brush Color { get => _color; set { _color = value; OnPropertyChanged(); } } public void UpdateColor(Brush color) => Color = color; }
As you can see, we inherit from VM (this is the base class that contains INotifyPropertyChanged), and also implement the interface we created earlier.
Having all this, we can combine all this in, let's create a MainViewModel:
public class MainViewModel { public ObservableCollection<ITabViewModel> TabItems { get; set; } = new ObservableCollection<ITabViewModel>(); public ITabViewModel SelectedTab { get; set; } public MainViewModel() { AddTestData(); //ΠΡΡΠ·ΠΈΠΌ Π½Π΅ΠΊΠΈΠ΅ ΡΠ΅ΡΡΠΎΠ²ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ TestOtherMethod(); //ΠΡΠ·ΡΠ²Π°Π΅ΠΌ ΠΌΠ΅ΡΠΎΠ΄ Ρ Π²ΡΠ΄Π΅Π»Π΅Π½Π½ΠΎΠΉ Π²ΠΊΠ»Π°Π΄ΠΊΠΈ } private void AddTestData() { //ΠΠ΅ΠΊΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅ TabItems.Add(new ViewModelA { Header = "ΠΠΊΠ»Π°Π΄ΠΊΠ° 1", Text = "ΠΡΠΈΠ²Π΅Ρ ΠΌΠΈΡ!", Color = Brushes.Aqua }); TabItems.Add(new ViewModelA { Header = "ΠΠΊΠ»Π°Π΄ΠΊΠ° 2", Text = "ΠΡΠΈΠ²Π΅Ρ Π·Π΅ΠΌΠ»Ρ!", Color = Brushes.Azure }); TabItems.Add(new ViewModelA { Header = "ΠΠΊΠ»Π°Π΄ΠΊΠ° 3", Text = "ΠΡΠΈΠ²Π΅Ρ ΠΊΠΎΡΠΌΠΎΡ!", Color = Brushes.Bisque }); //ΠΡΠ΄Π΅Π»ΡΠ΅ΠΌ ΠΏΠ΅ΡΠ²ΡΡ Π²ΠΊΠ»Π°Π΄ΠΊΡ SelectedTab = TabItems.FirstOrDefault(); } private void TestOtherMethod() { var item = SelectedTab as ViewModelA; item?.UpdateColor(Brushes.Green); } }
We tie the whole thing:
private MainViewModel MainViewModel { get; } = new MainViewModel(); public MainWindow() { InitializeComponent(); DataContext = MainViewModel; }
Now let's deal with XAML. In it, we need to create a TabControl, which will be bound via the ItemSource to our TabItems collection. We will also set the DataTemplate to the resources, so that under the defined ViewModel we get the required Control. Well, also tie the Header through the ItemContainerStyle. In the end, something like this will come out:
<TabControl ItemsSource="{Binding TabItems}" SelectedItem="{Binding SelectedTab}"> <TabControl.Resources> <DataTemplate DataType="{x:Type local:ViewModelA}"> <local:UserControl1 Text="{Binding Text}" Color="{Binding Color}" /> </DataTemplate> </TabControl.Resources> <TabControl.ItemContainerStyle> <Style TargetType="TabItem"> <Setter Property="Header" Value="{Binding Header}" /> </Style> </TabControl.ItemContainerStyle> </TabControl>
I will not show the Control itself; two DependencyProperty (Text and Color) are set there, the design itself consists of Border, inside of which there is a TextBlock.
Well, let's start and see what happens?

As you can see, we have 3 tabs, the first one we changed to green through the code.
With this approach, you get a convenient management of all tabs, as well as the possibility of their expansion by adding another Control'a and ViewModel.
Good luck in programming!
ΠΠΈΠΊΠ°ΠΊΠΈΡ "ItemSource", "Binding" Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ.- and in vain, oh, how in vain .. - EvgeniyZ