Search code examples
wpfxamltelerik

WPF binding to both view and viewmodel´s properties


This is originally a question about Teleriks TabbedWindow control, but its really a generic. Question. In a ItemTemplate, how to I bind to both the view and properties of the viewmodel

Below, my datasource is a list of Views (ie UserControls). I want to have the View presented in the ContentControl and some properties of the viewmodel presented in the header.

<telerik:RadTabbedWindow x:Class="Porter.Application.Views.MainWindow"
        ...
        ItemsSource="{Binding Tabs2}">
        
    <telerik:RadTabbedWindow.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding DataContext.TabHeader}" />
        </DataTemplate>
    </telerik:RadTabbedWindow.ItemTemplate>
    <telerik:RadTabbedWindow.ContentTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}" />
        </DataTemplate>
    </telerik:RadTabbedWindow.ContentTemplate>

</telerik:RadTabbedWindow>

UPDATED RESULT AFTER ANSWER FROM mm8

<telerik:RadTabbedWindow
     ItemsSource="{Binding Tabs2}" <!--list of ViewModels (lets say ViewModelBase.cs)-->
  ...>

<telerik:RadTabbedWindow.Resources>
        <DataTemplate DataType="{x:Type acc:SearchAccountsViewModel}">
            <acc:SearchAccountsView/>
        </DataTemplate> 
        <DataTemplate DataType="{x:Type hello:HelloWorldViewModel}">
            <hello:HelloWorldView/>
        </DataTemplate>

 </telerik:RadTabbedWindow.Resources>

    <telerik:RadTabbedWindow.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding TabHeader}" />
        </DataTemplate>
    </telerik:RadTabbedWindow.ItemTemplate>
    <telerik:RadTabbedWindow.ContentTemplate>
        <DataTemplate >
            <ContentControl Content="{Binding}" />
        </DataTemplate>
    </telerik:RadTabbedWindow.ContentTemplate>

</telerik:RadTabbedWindow>


Solution

  • The Tab2 property should return an IEnumerable<T> where the type T has some public properties that you bind to in the XAML markup.

    It may for example have a TabHeader property that you bind the header of the tab to in the ItemTemplate like this:

    <telerik:RadTabbedWindow x:Class="Porter.Application.Views.MainWindow"
            ...
            ItemsSource="{Binding Tabs2}">
    
        <telerik:RadTabbedWindow.ItemTemplate>
            <DataTemplate>
                <TextBlock Text = "{Binding TabHeader}" />
            </ DataTemplate >
        </ telerik:RadTabbedWindow.ItemTemplate>
    
    </telerik:RadTabbedWindow>
    

    The ContentTemplate should be resolved automatically provided that you have defined a DataTemplate for the type T in scope of the RadTabbedWindow, for example in your App.xaml. It's in this template that you add your UserControl:

    <DataTemplate DataType="{x:Type local:YourClass}">
        <local:UserControl1 />
    </DataTemplate>
    

    You should not create a UserControl in the view model and add it to Tabs2. This breaks what the MVVM pattern is all about, i.e. separation of concerns. A view model doesn't create views.

    If you don't have/want an implicit DataTemplate in App.xaml, you may of course also define the ContentTemplate inline:

    <telerik:RadTabbedWindow x:Class="Porter.Application.Views.MainWindow"
            ...
            ItemsSource="{Binding Tabs2}">
    
        <telerik:RadTabbedWindow.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding TabHeader}" />
            </DataTemplate>
        </telerik:RadTabbedWindow.ItemTemplate>
        <telerik:RadTabbedWindow.ContentTemplate>
            <DataTemplate>
                <local:UserControl1 />
            </DataTemplate>
        </telerik:RadTabbedWindow.ContentTemplate>
    
    </telerik:RadTabbedWindow>
    

    The key point is that you bind to properties of T in both templates and that T is a POCO and not a control of some kind.