c# mvvm 将视图绑定到带有标题的 tabcontrol [英] c# mvvm bind views to tabcontrol with header

查看:79
本文介绍了c# mvvm 将视图绑定到带有标题的 tabcontrol的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 wpf 程序,它有一个主视图(Window),它包含一个 TabControl 来显示几个不同的 UserControl 视图(sub-views,每个选项卡中一个).每个视图都有一个关联的视图模型.

I have a wpf programme with a main View (Window)which contains a TabControl to show several different UserControl Views (the sub-views, one in each tab). Every View has an associated ViewModel.

我希望绑定 TabControl 以便我只需要加载一个新的 sub-view 到 ApplicationViewModel 中,它就会出现在 TabControl代码>.

I wish to bind the TabControl so that I just need to load a new sub-view into the ApplicationViewModel and it will appear on the TabControl.

我已成功地将 sub-views 绑定到内容,但似乎无法在标题中获取任何内容.我希望将标题绑定到 sub-view 的 ViewModel 中的属性,特别是 TabTitle.

I have successfully bound the sub-views to the content, but cannot seem to get anything in the header. I wish to bind the header to a property in the sub-view's ViewModel, specifically TabTitle.

应用程序视图(DataTemplate 绑定不起作用):

Application View (DataTemplate binding not working):

<Window ...>
    <DockPanel>
        <TabControl ItemsSource="{Binding PageViews}" SelectedIndex="0"> <!--Working-->
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding DataContext.TabTitle}, Path=DataContext.TabTitle}" /> <!--Not Working-->
                </DataTemplate>    
            </TabControl.ItemTemplate>
        </TabControl>
    </DockPanel>
</Window>

Application ViewModel(ObservableObject 基本上实现了 INotifyPropertyChanged`):

Application ViewModel (ObservableObject basically implements INotifyPropertyChanged`):

class ApplicationViewModel : ObservableObject
{
    private DataManager Data;
    private ObservableCollection<UserControl> _pageViews;

    internal ApplicationViewModel()
    {
        Data = new DataManager();
        PageViews.Add(new Views.MembersView(new MembersViewModel(Data.DataSet)));
    }

    public ObservableCollection<UserControl> PageViews
    {
        get
        {
            if (_pageViews == null)
            {
                _pageViews = new ObservableCollection<UserControl>();
            }
            return _pageViews;
        }
    }

背后的MembersView代码:

The MembersView Code behind:

public partial class MembersView : UserControl
{
    public MembersView(MembersViewModel ViewModel)
    {
        InitializeComponent();
        DataContext = ViewModel;
    }
}

MembersViewModel(被截断):

MembersViewModel (truncated):

public class MembersViewModel : INotifyPropertyChanged
{
    public TabTitle { get; protected set; }

    public MembersViewModel(DataSet BBDataSet)
    {
        TabTitle = "Members";
    }

    //All view properties
}

我相信这很简单...

推荐答案

您正在将 TabControl 绑定到 UserControl 类型的集合.这意味着每个项目的数据上下文都属于 UserControl 类型.UserControl 中没有名为TabTitle"的属性,因此绑定将不起作用.

You are binding the TabControl to a collection of type UserControl. That means the data context for each item will be of type UserControl. There is no property named "TabTitle" in UserControl, so the binding will not work.

我认为您可以通过以下更改来完成您正在尝试做的事情:

I think what you are trying to do can be accomplished with the following changes:

  1. 让 ApplicationViewModel 公开一个 MemberViewModel 类型的集合,而不是 UserControl,并适当地填充它.
  2. 设置一个 ContentTemplate 来为 TabControl 中的项目创建视图:

  1. Have ApplicationViewModel expose a collection of type MembersViewModel, instead of UserControl, and populate it appropriately.
  2. Setup a ContentTemplate to create views for your items in the TabControl:

<TabControl.ContentTemplate>
    <DataTemplate DataType="{x:Type namespace:MembersViewModel}">
        <namespace:MembersView />
    </DataTemplate>
</TabControl.ContentTemplate>

(将命名空间:"替换为包含控件的 xaml 导入命名空间.)

(Replace "namespace:" with your xaml imported namespace containing your controls.)

更新 TabControl 中的 ItemTemplate,使其正确绑定到视图模型:

Update the ItemTemplate in your TabControl so it binds properly to the view model:

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

  • 更新MembersView 以获得无参数构造函数.视图上的 DataContext 将由 TabControl 为您设置.如果您需要从代码隐藏中访问视图模型,它应该在 InitializeComponent() 调用之后通过 DataContext 属性可用.

  • Update MembersView to have a parameterless constructor. The DataContext on the view will be set for you by the TabControl. If you need to access the view model from your code-behind, it should be available through the DataContext property after the InitializeComponent() call.

    任何时候使用 ItemsControl(及其扩展,如 ListBox、TreeView、TabControl 等),都不应实例化自己的项目视图.您总是希望设置一个模板,根据数据(或视图模型)实例化视图,并直接绑定到 ItemsSource 属性中的数据(或视图模型).这允许为您设置所有项目的数据上下文,以便您可以绑定到它们.

    Anytime you are working with ItemsControl (and its extensions such as ListBox, TreeView, TabControl, etc.), you should never be instantiating your own item views. You always want to setup a template that instantiates the view based on the data (or view model) and bind directly to the data (or view model) in the ItemsSource property. This allows all of the item's data contexts to be setup for you so you can bind to them.

    由于您有多个视图/视图模型配对,您需要稍微不同地定义模板:

    Since you have multiple view / viewmodel pairings, you will want to define your templates slightly differently:

    <TabControl ItemsSource="{Binding PageViews}" SelectedIndex="0">
        <TabControl.Resources>
            <DataTemplate DataType="{x:Type namespace:MembersViewModel}">
                <namespace:MembersView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type namespace:ClassesViewModel}">
                <namespace:ClassesView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type namespace:SessionsViewModel}">
                <namespace:SessionsView />
            </DataTemplate>
        </TabControl.Resources>
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding TabTitle}}" />
            </DataTemplate>    
        </TabControl.ItemTemplate>
    </TabControl>
    

    不同之处在于您要在资源中定义多个数据模板,每种类型一个.这意味着它每次遇到这些类型时都会使用这些模板.您仍然希望设置 ItemTemplate 以强制选项卡标题使用特定模板.但是不要设置ContentTemplate,允许内容使用资源中定义的数据模板.

    The difference is that you want to define multiple data templates, one for each type, in your resources. That means it will use those templates each time it encounters those types. You still want to set ItemTemplate to force the tab headers to use a specific template. However, do not set ContentTemplate, allowing the content to use the data templates defined in resources.

    我希望这是有道理的.

    附言您还可以在更高级别的资源字典中定义这些数据模板,例如在您的主窗口或您的应用程序中,如果您希望它们应用于您使用这些视图模型的每个地方的内容展示器,而不仅仅是在这个 TabControl.

    P.S. You can also define these data templates in a higher level resource dictionary, such as in your main window or your application, if you want them to apply to content presenters every place you use those view models, rather than only in this one TabControl.

    这篇关于c# mvvm 将视图绑定到带有标题的 tabcontrol的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆