gpt4 book ai didi

c# - 如果 MVVM 模型继承扩展到所有选项卡,为什么 Treeview 会扩展?

转载 作者:行者123 更新时间:2023-12-03 10:44:30 25 4
gpt4 key购买 nike

我不明白为什么当我在 WPF 中切换选项卡 TreeView 的扩展时,它会影响所有选项卡 TreeView 的扩展。我希望每个选项卡的 TreeView 彼此独立。这是一个非常简单的 MVVM 设置,有几个类。

enter image description here

这是项目中的文件

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:WpfApplication1"
xmlns:view="clr-namespace:WpfApplication1.View"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="250">

<Window.DataContext>
<data:ViewModel/>
</Window.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<!--<Button Content="Add" Command="{Binding AddCommand}" Grid.Row="0"></Button>-->
<TabControl x:Name="tabControl1" ItemsSource="{Binding TabItems}" Grid.Row="1" Background="LightBlue">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
</DataTemplate>
</TabControl.ItemTemplate>

<TabControl.ContentTemplate>
<DataTemplate>
<view:TabItemView />
</DataTemplate>
</TabControl.ContentTemplate>


</TabControl>

</Grid>
</Window>

TabItemView.xaml
<UserControl x:Class="WpfApplication1.View.TabItemView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Text="{Binding Content}" />
<TreeView Grid.Row="1" Background="Transparent">
<TreeViewItem Header="Favorites">
<TreeViewItem Header="USA"></TreeViewItem>
<TreeViewItem Header="Canada"></TreeViewItem>
<TreeViewItem Header="Mexico"></TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
</UserControl>

ViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
public class ViewModel
{
private ObservableCollection<TabItem> tabItems;

public ObservableCollection<TabItem> TabItems
{
get { return tabItems ?? (tabItems = new ObservableCollection<TabItem>()); }
}

public ViewModel()
{
TabItems.Add(new TabItem { Header = DateTime.Now.ToString("Tab 1"), Content = DateTime.Now.ToString("F") });
TabItems.Add(new TabItem { Header = DateTime.Now.ToString("Tab 2"), Content = DateTime.Now.ToString("F") });
TabItems.Add(new TabItem { Header = DateTime.Now.ToString("Tab 3"), Content = DateTime.Now.ToString("F") });
}
}

public class TabItem
{
public string Header { get; set; }
public string Content { get; set; }
}
}

最佳答案

TabControl为每个项目重复使用相同的内容元素。它所做的只是更改绑定(bind)的数据上下文(即您的 View 模型),更新绑定(bind)到 View 模型的模板化元素中的元素。因此,当您从一个选项卡切换到下一个选项卡时, View 的其他状态保持不变。

每次更改选项卡时都可以强制创建新的内容元素;一种方法是将内容元素的模板声明为资源,添加 x:Shared="False"到资源声明,然后将资源用作 Setter 的值应用于 Style针对TabItem类型。

通过 setter 将模板应用到每个 TabItem是必需的 - 和 TabItem这里我的意思是 WPF TabItem ,而不是您的 View 模型类,如果我是您,我会更改其名称以避免混淆。使用 x:Shared如果您只设置 TabControl.ContentTemplate 将无济于事直接一次。

例如:

  <TabControl.Resources>
<DataTemplate x:Key="tabItemTemplate" x:Shared="False">
<l:TabItemView />
</DataTemplate>
<s:Style TargetType="TabItem">
<Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=tabItemTemplate}"/>
</s:Style>
</TabControl.Resources>

但是,这会产生相反的效果:在从选项卡切换到选项卡时,不会保留每个项目的状态,而是完全重置 View 状态,因为每次切换时都会创建一个全新的内容元素。

如果这对您来说是可以接受的,那么这将正常工作。但是,如果您正在寻找每个选项卡以保留用户上次查看该选项卡时的任何配置,则您必须自己保留该状态。例如,您可以添加 bool属性到您的 View 模型以记住每个项目的当前设置并将其绑定(bind)到 IsExpanded顶级属性 TreeViewItem :

查看型号:
public class TabItem
{
public string Header { get; set; }
public string Content { get; set; }
public bool IsExpanded { get; set; }
}

查看:
<UserControl x:Class="TestSO33125188TreeViewTemplate.TabItemView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Text="{Binding Content}" />
<TreeView Grid.Row="1" Background="Transparent">
<TreeViewItem Header="Favorites" IsExpanded="{Binding IsExpanded, Mode=TwoWay}">
<TreeViewItem Header="USA"></TreeViewItem>
<TreeViewItem Header="Canada"></TreeViewItem>
<TreeViewItem Header="Mexico"></TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
</UserControl>

请注意,要使其正常工作,您需要显式设置绑定(bind) Mode属性(property)给 TwoWay , 默认为 OneWay并且不会以其他方式复制当前的 TreeViewItem.IsExpanded值返回给 View 模型。

另请注意,对于您的特定示例,您可以使用简单的容器 View 模型,而无需实现 INotifyPropertyChanged或类似的机制。每当更改当前选项卡时,WPF 都会强制将更新的属性值复制回 View 。但就个人而言,我会继续添加 INotifyPropertyChanged执行;在 WPF 不会自动检测到您已更新属性值的不同场景中,很容易发现自己重用该技术,从而导致令人沮丧的错误,需要一段时间才能跟踪和修复。

关于c# - 如果 MVVM 模型继承扩展到所有选项卡,为什么 Treeview 会扩展?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33125188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com