【问题标题】:Best way to bind a set of same-type ViewModels to a TabControl in MVVM / WPF将一组相同类型的 ViewModel 绑定到 MVVM / WPF 中的 TabControl 的最佳方法
【发布时间】:2015-03-18 21:10:55
【问题描述】:

我在 MVVM 项目中有一个现有的 ViewModel 和 View。实际上,此视图以特定样式的方式呈现项目集合。我将把这个现有的 ViewModel 称为“CollectionPresenter”。

到目前为止,这在 XAML 中已呈现如下:

<Grid>
    <ns:CollectionPresenter />
</Grid>

现在,我希望在选项卡视图中理想地提供这些“CollectionPresenter”视图模型的动态集合。

我的方法是定义这些“CollectionPresenters”的可观察集合,首先在构建父视图模型时创建它们。上面的 XAML 然后更改为如下所示:

<TabControl ItemsSource="{TemplateBinding CollectionPresenters}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding CollectionPresenterTitle}">
        </DataTemplate>
    <TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
         ... this is where things get confusing
    </TabControl.ContentTemplate>
<TabControl>

您可以在上面看到我的问题是 ContentTemplate。

当我加载它时,我得到一个选项卡控件,它的选项卡数量与我可观察的“CollectionPresenter”对象集合一样多。

但是,选项卡控件的内容始终为空。

这种方法正确吗?还有更好的方法吗?

编辑:添加一些额外的东西以使其更清晰

我尝试了以下方法,但它不起作用。带有选项卡控件的 XAML(绑定到“事物”工作正常):

<TabControl ItemsSource="{TemplateBinding Things}">
    <TabControl.ItemTemplate>
        <DataTemplate DataType="{x:Type viewModels:Thing}">
                <TextBlock Text="{Binding ThingName}" Width="200" Background="Blue" Foreground="White"/>
        </DataTemplate>
    </TabControl.ItemTemplate>    
    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type viewModels:Thing}">
                <TextBlock Text="{Binding ThingName}" Width="500" Height="500" Background="Blue" Foreground="White"/>
        </DataTemplate>
    </TabControl.ContentTemplate>  
</TabControl>

“事物”可观察集合的定义(位于带有选项卡控件的 XAML 的模板化父对象 (ParentObject) 内):

public static readonly DependencyProperty ThingsProperty =
DependencyProperty.Register("Things", typeof(ObservableCollection<Thing>), typeof(ParentObject), new PropertyMetadata(null));

public ObservableCollection<Thing> Things
{
    get { return (ObservableCollection<Thing>)GetValue(ThingsProperty); }
    set { SetValue(ThingsProperty, value); }
}   

“事物”视图模型的精简版:

public class Thing : ViewModelBase
{       
    public Thing()
    {
    }

    public void Initialise(ObservableCollection<Thing> things, string thingName)
    {            
        Things = things;
        ThingName = thingName;
    }

    public static readonly DependencyProperty ThingNameProperty =
    DependencyProperty.Register("ThingName", typeof(string), typeof(Thing), new PropertyMetadata(null));

    public string ThingName
    {
        get { return (string)GetValue(ThingNameProperty); }
        set { SetValue(ThingNameProperty, value); }
    }
}

【问题讨论】:

  • 你可能想看看我对WPF MVVM navigate views问题的回答。
  • 感谢@Sheridan,但没有帮助。我遇到的问题是 TabItem 的 ItemsSource 包含一组视图模型 - 但是当我定义 TabControl.ItemTemplate 并使用 {Binding ....} 引用视图模型的属性时它不起作用 - 并且视觉树不显示视图模型...它仅显示选项卡项,在 ItemTemplate 中具有可视项,但没有引用 ItemsSource 集合中的实际项...
  • 您的方法有缺陷,这就是为什么我为您提供了如何正确操作的链接。使用您的方法,您必须一次加载所有视图模型,这是对 RAM 的巨大且不必要的浪费。
  • 视图模型需要预先加载,因为选项卡纯粹是为了让屏幕上应该的内容同时分布在 2-5 个选项卡上(因为在单个选项卡上没有物理空间)。基本上我们不希望动态加载视图模型,我们希望它们都被预加载 - 但只是在屏幕上通过选项卡访问。
  • 链接的答案也向您展示了您的问题的解决方案......我将添加一个答案。

标签: c# wpf xaml


【解决方案1】:

看看我对WPF MVVM navigate views问题的回答,你可以看到:

<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
    <Views:MainView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:PersonViewModel}">
    <Views:PersonView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:CompanyViewModel}">
    <Views:CompanyView />
</DataTemplate>

现在,无论我们在应用程序中使用这些类型之一的实例,这些DataTemplates 都会告诉框架改为显示相关视图。

因此,您的解决方案是将一个DataTemplate 硬编码到TabControl.ItemTemplate 属性,而是将其留空。如果您使用多个DataTemplates 而不提供x:Key 值,那么当每个数据对象要在TabControl 中呈现时,它们将被隐式应用。


更新>>>

使用这些DataTemplates 应该让您的TabControl 看起来像这样:

<TabControl ItemsSource="{TemplateBinding Things}" />

我不知道你为什么在那里使用TemplateBinding,因为你不需要定义任何新模板来让它工作......因此,你应该使用普通的旧Binding .

您需要做的另一件事是为您希望以不同方式显示的集合中的每个项目使用不同的数据类型。您可以从 Thing 类派生自定义类,因此该集合仍然可以是 ObservableCollection&lt;Thing&gt; 类型。

【讨论】:

  • 我们的等价物。您的视图(例如 Views:CompanyView)由一个 ResourceDictionary 组成,它为目标类型“Thing”定义了一个样式和控制模板......这种方法仍然有效吗?
  • 您的问题中的DataTemplate 中只有一个TextBlock,所以我不太确定您的意思,但是如果您可以将其放入DataTemplate,那么是的,否则不行……试试看吧。
  • 是的,我已经简化了它,以免在帖子中编写大量代码。不过,我对原始帖子的最后一条评论仍然有效 - “ItemsSource”集合中的对象并未将自己呈现给我为每个选项卡项定义的数据模板,即使该模板是基本文本框......
  • 虽然它实际上解决了我的问题,但我认为那是因为我没有完整地解释它。我会赞成你的回答,因为我认为这很好......最后我覆盖了选项卡控件并实现了这一点。
猜你喜欢
  • 1970-01-01
  • 2018-10-25
  • 1970-01-01
  • 2013-11-10
  • 2010-12-31
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
相关资源
最近更新 更多