繁体   English   中英

如何从主视图模型中动态地用一个用户控件填充选项卡控件的项目列表的每个选项卡

[英]How to fill each tab of the tab control's itemslist with one user control dynamically from the mainviewmodel

我的MainView包含带有 ItemTemplate 和 ContentTemplate 的 TabControl。 TabControl 的 ItemsSource 绑定到我的MainViewModel中的属性ObservableCollection<TabViewModel> TabCollection

选项卡视图模型

    namespace LuxUs.ViewModels
{
    public class TabViewModel
    {
        public string Name { get; set; }
        public object VM {get; set;}      
        
        public TabViewModel(string name)
        {
            Name = name;
        }
        public TabViewModel(string name, object vm)
        {
            Name = name;
            VM = vm;          
        }        
    }
}

我想用它们的选项卡的 header 和 MainViewModel 动态创建选项卡,如下所示...:

主视图模型

    using System.Collections.ObjectModel;

namespace LuxUs.ViewModels
{
    public class MainViewModel : ObservableObject, IPageViewModel
    {
        
        public ObservableCollection<TabViewModel> TabCollection { get; set; }

        public MainViewModel()
        {
            TabCollection = new ObservableCollection<TabViewModel>();
            TabCollection.Add(new TabViewModel("Dachdefinition", new DachdefinitionViewModel()));
            TabCollection.Add(new TabViewModel("Baukörperdefinition"));
            TabCollection.Add(new TabViewModel("Fassade"));
            TabCollection.Add(new TabViewModel("Raumdefinition"));
            TabCollection.Add(new TabViewModel("Treppenloch | Galerieöffnung"));
            
        }       
    }
}

看法:

<UserControl  x:Class="LuxUs.Views.MainView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:LuxUs.Views"
             xmlns:models="clr-namespace:LuxUs.Models"
             xmlns:vm="clr-namespace:LuxUs.ViewModels"
             mc:Ignorable="d">
    <Grid>
        <Grid>
            <TabControl Style="{DynamicResource TabControlStyle}" ItemsSource="{Binding TabCollection}" >
              
                <TabControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}"/>
                    </DataTemplate>
                </TabControl.ItemTemplate>
                <TabControl.ContentTemplate>
                    <DataTemplate>
                        <UserControl>
                            <ContentControl Content="{Binding VM}" />
                        </UserControl>
                    </DataTemplate>
                </TabControl.ContentTemplate>
            </TabControl>
        </Grid>
    </Grid>
</UserControl>

...但每个选项卡的内容不会显示。 相反,我得到了这个文本。 ViewModel 是正确的,但它应该加载视图而不是显示此文本,当然:

视图的屏幕截图

第一个选项卡的 ViewModel DachdefinitionViewModel只有一个空的构造函数:

    using System.Collections.ObjectModel;

namespace LuxUs.ViewModels
{
    public sealed class DachdefinitionViewModel : ObservableObject
    {       
        public DachdefinitionViewModel()
        {
  
        }  
    }
}

这是它的观点Dachdefinition.xaml

    <UserControl x:Class="LuxUs.Views.Dachdefinition"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:LuxUs.Views"
             xmlns:vm="clr-namespace:LuxUs.ViewModels"
             mc:Ignorable="d">
    <UserControl.DataContext>
        <vm:DachdefinitionViewModel></vm:DachdefinitionViewModel>
    </UserControl.DataContext>
    <Grid Margin="50">
...
...
...
 </Grid>
</UserControl>

这里的绑定是正确的还是我需要以不同的方式绑定? 为什么视图没有显示在第一个选项卡中?

您的 TabControl 声明应如下所示:

<TabControl ItemsSource="{Binding TabCollection}">
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type vm:DachdefinitionViewModel}">
            <local:Dachdefinition/>
        </DataTemplate>
    </TabControl.Resources>
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{Binding Name}"/>
            <Setter Property="Content" Value="{Binding VM}"/>
        </Style>
    </TabControl.ItemContainerStyle>
</TabControl>

并且Dachdefinition UserControl 不能设置自己的DataContext 属性,因为DataContext 值应该是从控件的父元素,即TabItem 继承的。

<UserControl x:Class="LuxUs.Views.Dachdefinition" ...>
   <!--
       do not set UserControl.DataContext here
   -->
   <Grid Margin="50">
       ...
   </Grid>
</UserControl>

您需要通过 DataTemplate 将视图 model 与正确视图连接起来。

DataTemplate 为没有它的数据类型(您的视图模型)提供可视化表示。 如果你不指定DataTemplate,你会得到默认的:TextBlock,字符串表示为object(ToString()方法的结果,默认为类型名)。

<Grid>
    <Grid.Resources>
         <DataTemplate DataType="{x:Type vm:DachdefinitionViewModel}">
              <views:Dachdefinition />
         </DataTemplate>
    </Grid.Resources>

    <TabControl Style="{DynamicResource TabControlStyle}" 
                ItemsSource="{Binding TabCollection}" >
      
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <UserControl>
                    <ContentControl Content="{Binding VM}" />
                </UserControl>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

是的,数据绑定存在问题。 <ContentControl Content="{Binding VM}" />

此行将仅显示绑定到它的 object 的 ToString() 值。 (在这种情况下是虚拟机)。

相反,您可以尝试使用 ContentTemplateSelection ,您可以在运行时根据绑定到它的 object 的类型来选择 ContentTemplate 的类型。

class TabContentTemplateSelector:DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate DachdeTemplate { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is TabViewModel tabViewModel)
        {
            if (tabViewModel.VM != null && tabViewModel.VM is DachdefinitionViewModel)
            {
                return DachdeTemplate;
            }
            else
            {
                return DefaultTemplate;
            }
        }
        return base.SelectTemplate(item, container);
    }
}


   <DataTemplate x:Key="DachdeTemplate">
      
    </DataTemplate>

    <DataTemplate x:Key="SomeOtherTemplate">
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>


    <local:TabContentTemplateSelector x:Key="myTabContentTemplateSelector"
                                      DachdeTemplate="{StaticResource DachdeTemplate}"
                                      DefaultTemplate="{StaticResource 
                                      SomeOtherTemplate}"
                                      />
</UserControl.Resources>
<Grid> 
        <TabControl  ItemsSource="{Binding TabCollection}" 
                    ContentTemplateSelector="{StaticResource 
                    myTabContentTemplateSelector}" > 
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </TabControl.ItemTemplate> 
        </TabControl>
    </Grid> 

https://www.c-sharpcorner.com/UploadFile/41e70f/dynamically-selecting-datatemplate-for-wpf-listview-way-1/检查如何动态更改模板。在模板中,您可以使用任何类型的用户控制。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM