MVVM Binding Views to TabControlItems - Views don't display

孤街浪徒 提交于 2019-12-24 07:48:43

问题


I want to display different views in TabControlItems in my MainView.

To do this I've created a class like this :

public sealed class TabItem
{
    public string Header { get; set; }
    public ViewModelBase Content { get; set; }
}

That I call in a Listin my ViewModel :

private ObservableCollection<TabItem> _views;
public ObservableCollection<TabItem> Views
{
    get { return _views; }
    set
    {
        _views = value;
        RaisePropertyChanged(() => Views);
    }
}

public IndexMainViewModel()
{
    Views = new ObservableCollection<TabItem>();
    Views.Add(new TabItem { Header = "Export", Content = new ExportViewModel() });
    Views.Add(new TabItem { Header = "Import", Content = new ImportViewModel() });  
}

EDIT And then display in my View :

<window xmlns:views="clr-namespace:EDICOT_Module_Import_Export_Articles.View"
xmlns:vm="clr-namespace:EDICOT_Module_Import_Export_Articles.ViewModel"
xmlns:model="clr-namespace:EDICOT_Module_Import_Export_Articles.Model.Classes"
DataContext="{Binding IndexMainVM, Source={StaticResource Locator}}">

   <TabControl ItemsSource="{Binding Views}">
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type model:TabItem}">
            <DataTemplate.Resources>
                <DataTemplate DataType="{x:Type vm:ImportViewModel}">
                    <views:ImportView />
                </DataTemplate>
                <DataTemplate DataType="{x:Type vm:ExportViewModel}">
                    <views:ExportView />
                </DataTemplate>
            </DataTemplate.Resources>
            <ContentControl Content="{Binding Content}"/>
        </DataTemplate>
    </TabControl.Resources>

    <TabControl.ItemTemplate >
        <DataTemplate >
            <TextBlock Text="{Binding Header}"/>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

The problem is that it displays only the header but not the content (the view), it shows instead the path to the TabItem class.

To give more infos : I've truncated the code to keep only what the topic needs and I use MVVM Light.

I really don't get what I miss here ! Thx for your help.


回答1:


The problem is that each tab is bound to an instance of TabItem. You have DataTemplates for vm:ExportViewModel and vm:ImportViewModel. Do you see your error now?

There are many solutions for this. Simplest is to move the Header text into the base view model and bind that Tab control to a collection of ViewModels.

Another alternative would be to add a DataTemplate for TabItem, stick a ContentControl in it, and bind that to the view model. Here's some xaml-like pseudocode to illustrate this idea:

<DataTemplate DataType="{x:Type vm:TabItem}">
    <ContentControl Content={Binding Content}" />
</DataTemplate>

You may have to move the templates for your view models into the resources of the ContentControl, but I don't think that's necessary. You might need to tweak the TabItem data template so that it fills the tab window as well.

A third option would be to implement a custom DataTemplateSelector and use that in your Tab control. In this selector, simply crack open your TabItem and look at the Content property for the type. You can browse the source code for the default DataTemplateSelector to find out how to get the correct template for the given type. This method gets your hands deep in the gore of WPF, which is an interesting trip. I've done it once, and I prefer to not do it again. Actually, for your needs, the trip won't be as bad as mine. The default selector doesn't do squat, so returning base.SelectTemplate is worthless. I dug around in the framework for an example of how it should be implemented.

public class TabItemDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate
        SelectTemplate(object item, DependencyObject container)
    {
        var viewModel = item as TabItem;
        if (item == null)
            return null;
        else
            item = viewModel.Content;

        FrameworkElement fe = null;
        if (container is ContentPresenter)
            fe = (container as ContentPresenter)
                    .TemplatedParent as FrameworkElement;
        else
            fe = container as FrameworkElement;

        var key = new DataTemplateKey(item.GetType());
        return fe.TryFindResource(key) as DataTemplate;
    }
}

add an instance of that to a Resource somewhere

<derp:TabItemDataTemplateSelector x:Key="tidts"/>

then bind that to ContentTemplateSelector

<TabControl ItemsSource="{Binding Views}"
            ContentTemplateSelector={StaticResource tidts}>


来源:https://stackoverflow.com/questions/37328616/mvvm-binding-views-to-tabcontrolitems-views-dont-display

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!