David P
David P

Reputation: 33

C# / WPF Bind in TabControl ItemsSource to property in code behind of List item

In my ViewModel I have a BindingList which holds my Views that should be displayed as tabs in my TabControl. The text for the tab is defined in the code behind of the view. I also defined a simple test class to test the binding which works perfectly. Only the binding to the code behind property does not work.

Xaml code for my TabControl:

<TabControl ItemsSource="{Binding TabControlContentList}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=DisplayName, FallbackValue=FallbackValue}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

The BindingList which it is bound to:

void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

public BindingList<object> TabControlContentList
{
    get => tabControlContentList;
    set
    {
        tabControlContentList = value;
        RaisePropertyChanged();
    }
}
private BindingList<object> tabControlContentList = new BindingList<object>();

Test class:

class ControlTest
{
    public string DisplayName { get; private set; } = "";

    public ControlTest(string name) => DisplayName = name;
}

Xaml code behind of AnalysisView.xaml.cs:

public partial class AnalysisView
{
    public string DisplayName { get; private set; } = "Analysis";

    public AnalysisView()
    {
        InitializeComponent();
    }
} 

In my ViewModel I have the following code:

public AnalysisView analysisView = new AnalysisView();
TabControlContentList.Clear();
TabControlContentList.Add(new ControlTest("Menu 1"));
TabControlContentList.Add(new ControlTest("Menu 2"));
TabControlContentList.Add(analysisView);
TabControlContentList.Add(new ControlTest("Menu 3"));
TabControlContentList.Add(new ControlTest("Menu 4"));

My TabControl then shows five tabs. First two have the text "Menu 1" and "Menu 2" on them, the third one reads "FallbackValue", followed by "Menu 3" and "Menu 4".

I have no idea anymore why the binding on the property in code behind in AnalysisView.xaml.cs does not work. Is this maybe a general Wpf thing?

Upvotes: 0

Views: 841

Answers (1)

Keithernet
Keithernet

Reputation: 2509

Before I present my answer, I highly recommend that you download and learn how to use Snoop for WPF, or use the Visual Studio built-in XAML runtime inspection tools. These allow you to look at bindings, data context, etc.

The main reason why your code doesn't work, is that a UserControl doesn't have a DataContext by default.

So, updating your AnalysisView like so will give it a DataContext pointing to itself:

public AnalysisView()
{
    InitializeComponent();
    DataContext = this;
}

However, the DataContext in a UserControl won't flow into your DataTemplate like your other objects. To make it work, you need to change your binding like so:

<DataTemplate>
    <TextBlock Text="{Binding Path=DataContext.DisplayName, FallbackValue=ERROR!, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" />
</DataTemplate>

Working with UserControls like this feels like a hack. So you might want to look for ways to design whatever app you're building a little differently.

Also, the code in your sample is not using INotifyPropertyChanged for properties, so you won't be getting any change notifications. You might want to learn more about the MVVM pattern.

Upvotes: 0

Related Questions