介绍:
我目前正在开发一个应用程序,其中数据应显示在 TabView 中。默认情况下,将打开一个“主页”选项卡,显示一个列表框。单击此框中的条目后,将在新选项卡中打开详细视图。
该应用程序是在 MVVM 架构中创建的。“MainViewModel”包含一个集合,其中 ViewModel 填充 TabView。我正在尝试使用 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 到处都是:
期望的结果
对我来说奇怪的是,当我使用“内联”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
问题
如何使用 TemplateSelector 正确创建 TabViewItems,其中 Header 和 Content 基于 DataTemplate?在搜索类似问题时,我找到了旧项目的解决方案,当简单地将 TabViewItem 嵌套在 DataTemplate 中时,这似乎可以正常工作,这显然不是这里的情况。