简体   繁体   English

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

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

My MainView contains a TabControl with an ItemTemplate and a ContentTemplate.我的MainView包含带有 ItemTemplate 和 ContentTemplate 的 TabControl。 The TabControl's ItemsSource is bound to the Property ObservableCollection<TabViewModel> TabCollection in my MainViewModel . TabControl 的 ItemsSource 绑定到我的MainViewModel中的属性ObservableCollection<TabViewModel> TabCollection

TabViewModel :选项卡视图模型

    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;          
        }        
    }
}

I want to create the tabs with their tab's header AND content dynamically from the MainViewModel like this...:我想用它们的选项卡的 header 和 MainViewModel 动态创建选项卡,如下所示...:

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"));
            
        }       
    }
}

View:看法:

<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>

... but the content of each tab won't show. ...但每个选项卡的内容不会显示。 Instead, I get this text.相反,我得到了这个文本。 The ViewModel ist the correct one but it should load the view instead of showing this text, of course: ViewModel 是正确的,但它应该加载视图而不是显示此文本,当然:

视图的屏幕截图

The first tab's ViewModel DachdefinitionViewModel has only an empty constructor:第一个选项卡的 ViewModel DachdefinitionViewModel只有一个空的构造函数:

    using System.Collections.ObjectModel;

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

And here is its view Dachdefinition.xaml :这是它的观点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>

Is the binding correct here or do I need to bind differently?这里的绑定是正确的还是我需要以不同的方式绑定? Why is the view not showing up inside the first tab?为什么视图没有显示在第一个选项卡中?

Your TabControl declaration should look like this:您的 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>

And the Dachdefinition UserControl must not set its own DataContext property, because the DataContext value is supposed to be inherit from the control's parent element, ie the TabItem.并且Dachdefinition UserControl 不能设置自己的DataContext 属性,因为DataContext 值应该是从控件的父元素,即TabItem 继承的。

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

you need to connect view model with correct view via DataTemplate.您需要通过 DataTemplate 将视图 model 与正确视图连接起来。

DataTemplate provides visual representation for data type which doesn't have it (your view model). DataTemplate 为没有它的数据类型(您的视图模型)提供可视化表示。 If you don't specify DataTemplate, you will get default one: TextBlock with string representation of object (result of ToString() method, default to type name).如果你不指定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>

Yes there is a problem in databinding.是的,数据绑定存在问题。 at <ContentControl Content="{Binding VM}" /><ContentControl Content="{Binding VM}" />

This line would just display ToString() value of the object bound to it.此行将仅显示绑定到它的 object 的 ToString() 值。 (VM in this case). (在这种情况下是虚拟机)。

Instead you can try using ContentTemplateSelection where you can choose the type of ContentTemplate in run time based on the type of object bound to it.相反,您可以尝试使用 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/ Check this for how to dynamically change template.. In the template you can use any kind of user control. 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