在 WinUI 3 中使用 TabItemTemplateSelector 和 TemplateSelector 导致奇怪的嵌套控件

问题描述

简介:

我目前正在开发一个应用程序,其中数据应显示在 TabView 中。认情况下,将打开一个“主页”选项卡,显示一个列表框。单击此框中的条目后,将在新选项卡中打开详细信息视图。

该应用程序是在 MVVM 架构中创建的。 “Mainviewmodel”包含一个集合,其中包含填充 TabView 的 viewmodel。我正在尝试使用 DataTemplateSelector 基于 viewmodel 类切换 DataTemplates。

该项目正在使用以下依赖项:

<packagereference Include="CommunityToolkit.Mvvm" Version="7.0.2" />
<packagereference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.0.2" />
<packagereference Include="Microsoft.ProjectReunion" Version="0.5.7" />
<packagereference Include="Microsoft.ProjectReunion.Foundation" Version="0.5.7" />
<packagereference Include="Microsoft.ProjectReunion.WinUI" Version="0.5.7" />

示例代码

MainWindow.xaml.cs 包含 viewmodel 和模板选择器

using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;


namespace TestingApp
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }
    }

    public class TabItemDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate HomeTemplate { get; set; }
        public DataTemplate DetailTemplate { get; set; }

        protected override DataTemplate SelectTemplateCore(object item,DependencyObject container)
        {
            switch (item)
            {
                case HoMetabviewmodel:
                    return HomeTemplate;
                case DetailTabviewmodel:
                    return DetailTemplate;
                default:
                    throw new ArgumentException("Invalid viewmodel type supplied as item");
            }
        }
    }

    public class MainWindowviewmodel : ObservableObject
    {
        private ObservableCollection<ObservableObject> tabItems;
        public ObservableCollection<ObservableObject> TabItems { get => tabItems; set => SetProperty(ref tabItems,value); }

        public MainWindowviewmodel()
        {
            TabItems = new ObservableCollection<ObservableObject>();
            TabItems.Add(new HoMetabviewmodel());
            TabItems.Add(new DetailTabviewmodel());
            TabItems.Add(new DetailTabviewmodel());
        }
    }

    public class HoMetabviewmodel : ObservableObject
    {
        public string Header { get; set; } = "Home";
        public string Detail { get; set; } = "I'm the HomeView";
    }

    public class DetailTabviewmodel : ObservableObject
    {
        public string Title { get; set; } = "Detail"; // Different Name to make the classes a bit different
        public string Detail { get; set; } = "Hello from the Details!";
    }
}

MainWindow.xaml 只包含一个 TabView

<Window
    x:Class="TestingApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestingApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.DataContext>
            <local:MainWindowviewmodel />
        </Grid.DataContext>

        <Grid.Resources>
            <DataTemplate x:Key="HomeTemplate">
                <TabViewItem Header="{Binding Header}" />
            </DataTemplate>

            <DataTemplate x:Key="DetailTemplate">
                <TabViewItem Header="{Binding Title}" />
            </DataTemplate>
            
            <local:TabItemDataTemplateSelector x:Key="TemplateSelector" DetailTemplate="{StaticResource DetailTemplate}" HomeTemplate="{StaticResource HomeTemplate}" />
        </Grid.Resources>

        <TabView TabItemsSource="{Binding TabItems}" TabItemTemplateSelector="{StaticResource TemplateSelector}">
        </TabView>
    </Grid>
</Window>

结果

上面的代码创建了一个奇怪的嵌套结果,看起来模板被多次应用于标题内容,导致TabViewItems到处都是:

Actual Result

想要的结果

对我来说奇怪的是,当我使用“内联”TabItemTemplate 时,结果很好,绑定有效。

    <Grid>
        <Grid.DataContext>
            <local:MainWindowviewmodel />
        </Grid.DataContext>

        <TabView TabItemsSource="{Binding TabItems}">
            <TabView.TabItemTemplate>
                <DataTemplate>
                    <TabViewItem Header="Tab">
                        <TextBlock Text="{Binding Detail}" />
                    </TabViewItem>
                </DataTemplate>
            </TabView.TabItemTemplate>
        </TabView>
    </Grid

working template sample #1

working template sample #2

问题

如何使用 TemplateSelector 正确创建 TabViewItem,其中 Header 和 Content 基于 DataTemplate?在搜索类似问题时,我找到了旧项目的解决方案,当简单地在 DataTemplate 中嵌套 TabViewItem 时,这些解决方案似乎可以正常工作,而这里显然不是这种情况。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...