英文:
Winui TabView change tab view model (and layout) depending on tab type
问题
我有一个选项卡视图和多个视图模型,选项卡视图可以显示每个选项卡的不同视图模型,例如 ViewModel1 和 ViewModel2。每个选项卡还会根据其模型类型拥有自己的布局。我面临的问题是无法让视图更改并加载正确的模型。在WPF中,这相对简单,我可以编写如下的数据模板,它将呈现正确的视图:
<TabControl.Resources>
<DataTemplate DataType="{x:Type tab:ViewModel1}">
<!-- ViewModel1 的视图 -->
</DataTemplate>
<DataTemplate DataType="{x:Type tab:ViewModel2}">
<!-- ViewModel2 的视图 -->
</DataTemplate>
</TabControl.Resources>
然而,在 WinUI 中,不再支持 x:Type,我很难找到一种动态更改视图和模型的方法。
目前,我有一个名为 ITab 的接口,该接口存储 TabName 和 TabType(Model1 或 Model2):
string Name { get; set; }
TabType TabType { get; }
任何想要成为选项卡集合一部分的视图模型都必须实现此接口。然后,在父视图模型中,我有一个 ITab 的可观察集合,它绑定到选项卡的 ItemsSource。
在 XAML 中,我有以下代码(其中一些是从旧的 WPF 项目复制过来的):
<TabView.Resources>
<DataTemplate x:DataType="model:Model1" x:Key="model1">
<!-- Model1 的视图 -->
</DataTemplate>
<DataTemplate x:DataType="model:Model2" x:Key="model2">
<!-- Model2 的视图 -->
</DataTemplate>
</TabView.Resources>
<TabView.TabItemTemplate>
<DataTemplate x:DataType="itab:ITab">
<TabViewItem Header="{Binding Name}">
<TextBlock>文本</TextBlock>
</TabViewItem>
</DataTemplate>
</TabView.TabItemTemplate>
这会渲染选项卡并显示选项卡名称,但是这仅适用于一个视图模型,如何指定如果 TabType 是 Model2,则使用 Model2,否则使用 Model1 呢?
我尝试创建一个自定义的 TabItemTemplateSelector:
<TabView.TabItems>
<DataTemplate x:DataType="itab:ITab">
<TabViewItem Header="{Binding Name}">
<templates:TabItemTemplateSelector Model1="{StaticResource model1}" Model2="{StaticResource model2}" />
</TabViewItem>
</DataTemplate>
</TabView.TabItems>
public class TabItemTemplateSelector : DataTemplateSelector
{
private DataTemplate _model1;
private DataTemplate _model2;
public DataTemplate Model1
{
get { return _model1; }
set { _model1 = value; }
}
public DataTemplate Model2
{
get { return _model2; }
set { _model2 = value; }
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item != null)
{
var tab = (ITab)item;
switch (tab.TabType)
{
case TabType.Model1:
return _model1;
case TabType.Model2:
return _model2;
default:
throw new InvalidOperationException("未知的选项卡类型");
}
}
return base.SelectTemplateCore(item, container);
}
}
然而,当渲染时,它显示类名,例如 MyApp.Models.TabItemSelector。
英文:
I have a tab view and multiple viewmodels which the tab view can display, each tab can be a type of say ViewModel1 and ViewModel2, they will also have their own layout depending on the type of model it is. The issue I am facing is that I cannot get the view to change and load the correct model, it WPF this was fairly straight forward I could write something like the below for data template and it would render the correct view:
<TabControl.Resources><DataTemplate DataType="{x:Type tab:ViewModel}">
</DataTemplate>
<DataTemplate DataType="{x:Type tab:ViewModel2}">
</DataTemplate>
</TabControl.Resources>
However, with winui I x:Type is no longer available, and I am struggling to figure out a way of dynamically changing the view and model.
Current I have an interface called ITab, this interface stores the TabName and the TabType (Model1 or 2)
string Name { get; set; }
TabType TabType { get; }
Any viewmodel which wants to be part of the tab collection, must implement this interface. In the parent viewmodel I then have an observable collection of ITab, this is bind to the Tabs ItemsSource.
In the XAML I have this code here, (some of this will copied from an old WPF project)
<TabView.Resources>
<DataTemplate x:DataType="model:Model1" x:Key="model1">
<Grid> <!--VIEW FOR MODEL 1--> </Grid>
</DataTemplate>
<DataTemplate x:DataType="model:Model1" x:Key="model2"> <!--VIEW FOR MODEL 2--> </DataTemplate>
</TabView.Resources>
<TabView.TabItemTemplate>
<DataTemplate x:DataType="itab:ITab">
<TabViewItem Header="{Binding Name}">
<TextBlock>Text</TextBlock>
</TabViewItem>
</DataTemplate>
</TabView.TabItemTemplate>
This renders the tab and display the tab name, however, this only happens for one viewmodel, how do I specify to use Model2 if the tabtype is Model2 else Model1?
I did try making a custom TabItemTemplateSelector
<TabView.TabItems>
<DataTemplate x:DataType="itab:ITab">
<TabViewItem Header="{Binding Name}">
<templates:TabItemTemplateSelector Model1="{StaticResource model1}" Model2="{StaticResource model2}" />
</TabViewItem>
</DataTemplate>
</TabView.TabItems>
public class TabItemTemplateSelector : DataTemplateSelector { private DataTemplate _model1; private DataTemplate _model2;
public DataTemplate Model1
{
get { return _model1; }
set { _model1 = value; }
}
public DataTemplate Model2
{
get { return _model2; }
set { _model2 = value; }
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item != null)
{
var tab = (ITab)item;
switch (tab.TabType)
{
case TabType.Model1:
return _model1;
case TabType.Model2:
return _model2;
default:
throw new InvalidOperationException("Uknown tab type");
}
}
return base.SelectTemplateCore(item, container);
}
}
However, when this is rendered it displays the class name e.g. MyApp.Models.TabItemSelector
答案1
得分: 1
你可以参考这个帖子。<templates:TabItemTemplateSelector Model1="{S...
应该用作TabView的属性TabView.TabItemTemplateSelector,而不是在DataTemplate
中使用。
所以你需要在TabView的上级容器中定义DataTemplateSelector资源,使用TabItemTemplateSelector
来使用DataTemplateSelector。
<Grid>
<Grid.Resources>
<DataTemplate x:DataType="model:Model1" x:Key="model1">
<Grid>
<!--MODEL 1的视图-->
</Grid>
</DataTemplate>
<DataTemplate x:DataType="model:Model1" x:Key="model2">
<!--MODEL 2的视图-->
</DataTemplate>
<local:TabItemTemplateSelector x:Key="MyDataTemplateSelector" Model1="{StaticResource model1}" Model2="{StaticResource model2}" />
</Grid.Resources>
<TabView TabItemsSource="{x:Bind TabList}" TabItemTemplateSelector="{StaticResource MyDataTemplateSelector}">
</TabView>
</Grid>
英文:
You can refer to this thread. <templates:TabItemTemplateSelector Model1="{S...
should be used as TabView Property TabView.TabItemTemplateSelector, instead of in DataTemplate
.
So you need to define DataTemplateSelector resources in the upper level container of TabView, use TabItemTemplateSelector
to use the DataTemplateSelector.
<Grid>
<Grid.Resources>
<DataTemplate x:DataType="model:Model1" x:Key="model1">
<Grid>
<!--VIEW FOR MODEL 1-->
</Grid>
</DataTemplate>
<DataTemplate x:DataType="model:Model1" x:Key="model2">
<!--VIEW FOR MODEL 2-->
</DataTemplate>
<local:TabItemTemplateSelector x:Key="MyDataTemplateSelector" Model1="{StaticResource model1}" Model2="{StaticResource model2}" />
</Grid.Resources>
<TabView TabItemsSource="{x:Bind TabList}" TabItemTemplateSelector="{StaticResource MyDataTemplateSelector}">
</TabView>
</Grid>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论