Reputation: 814
I'm trying to make a TabControl
, populated with few UserControl
s each with a separate ViewModel.
I've declared it in my XAML like this:
<TabControl Margin="10,10,10,40" ItemsSource="{Binding Test}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontSize="16" Padding="5"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
As you can see I'm trying to obtain the name of the tab through a property located in it's View Model:
public class GeneralTabViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public GeneralTabViewModel()
{
Name = "Name";
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The View Model associated with the window that holds the TabControl
is declared as follows:
public class SettingsViewModel
{
public ObservableCollection<UserControl> Test { get; set; }
public SettingsViewModel()
{
Test = new ObservableCollection<UserControl>
{
new GeneralTab(),
new GeneralTab()
};
}
}
Building the program like this yields an empty Header for the 2 tabs.
How can I bind the TextBlock
's Text
property to the Name
property located in the View Model of the UserControl
?
If I change the ItemSource
type from ObservableCollection<UserControl>
to ObservableCollection<GeneralTabViewModel>
I will be able to access the property, but how am I going to visualize the UserControl
than?
Upvotes: 0
Views: 41
Reputation: 128061
It is wrong to have UserControls in your SettingsViewModel. It should instead have a collection of GeneralTabViewModels:
public class SettingsViewModel
{
public ObservableCollection<GeneralTabViewModel> Test { get; }
public SettingsViewModel()
{
Test = new ObservableCollection<GeneralTabViewModel>
{
new GeneralTabViewModel { Name = "Tab 1" },
new GeneralTabViewModel { Name = "Tab 2" }
};
}
}
You would then use the UserControl in the ItemTemplate of your TabControl:
<TabControl Margin="10,10,10,40" ItemsSource="{Binding Test}">
<TabControl.ItemTemplate>
<DataTemplate>
<GeneralTab TabName="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
In order to make ths work, it is important that GeneralTab does not explicitly set its DataContext property. It may look like this:
<UserControl x:Class="YourNamespace.GeneralTab" ...>
<Grid>
<TextBlock FontSize="16" Padding="5"
Text="{Binding TabName,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</Grid>
</UserControl>
with this dependency property in its code behind:
public static readonly DependencyProperty TabNameProperty =
DependencyProperty.Register(nameof(TabName), typeof(string), typeof(GeneralTab));
public string TabName
{
get { return (string)GetValue(TabNameProperty); }
set { SetValue(TabNameProperty, value); }
}
Upvotes: 1