在WPF MVVM ContentControl中切换UserControls时如何缓存它们?

fnvucqvd  于 2023-06-07  发布在  其他
关注(0)|答案(1)|浏览(283)

WPF / MVVM /内容控制
实现一个使用按钮在UserControls之间切换的应用:App Diagram
该方法将UserControlDataTemplates分配给不同的视图模型,并通过按钮切换视图模型。问题是每个UserControl都是重新示例化的,这会导致集成的旧版Windows窗体控件出现问题。有没有一种方法可以实现这种缓存UserControls的方法?我想我可以加载所有内容并更改可见性作为备用,但想知道是否有什么我错过了。

MainWindow.xaml

<Window x:Class="ContentControl.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="clr-namespace:ContentControl.ViewModel"
        xmlns:local="clr-namespace:ContentControl.View"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <vm:MainViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:UC1ViewModel}">
            <local:UC1UserControl/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:UC2ViewModel}">
            <local:UC2UserControl/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0">
            <Button Command="{Binding UpdateContentCommand}" CommandParameter="uc1">UC 1</Button>
            <Button Command="{Binding UpdateContentCommand}" CommandParameter="uc2">UC 2</Button>
        </StackPanel>
        <ContentControl Grid.Column="1" Content="{Binding SelectedViewModel}"/>
    </Grid>
</Window>

UpdateContentCommand.cs

internal class UpdateContentCommand : ICommand
{
   public event EventHandler? CanExecuteChanged;
   private MainViewModel vm;

   public bool CanExecute(object? parameter)
   {
       return true;
   }

   public void Execute(object? parameter)
   {
       if (parameter is string p)
       {
           if (p.ToLower() == "uc1")
           {
                vm.SelectedViewModel = vm.UC1VM;
           }
           else if (p.ToLower() == "uc2")
           {
               vm.SelectedViewModel = vm.UC2VM;
           }
       }
}

   public UpdateContentCommand(MainViewModel vm)
   {
       this.vm = vm;
   }
}
gfttwv5a

gfttwv5a1#

您可以定义希望作为资源重用的控件示例。这样,XAML引擎将只创建一个共享示例。请记住,此示例只能添加到可视化树的 * 单个 * 位置。这意味着,你不能在DataTemplate中使用这个特定的示例,并使它成为例如StackPanel同时。如果需要示例化DataTemplate的多个示例(例如ListBox中的项目),这也不起作用。

<Window.Resources>
  <local:UC1UserControl x:Key="SharedUC1UserControl" />
  <local:UC1UserControl x:Key="SharedUC2UserControl" />

  <DataTemplate DataType="{x:Type vm:UC1ViewModel}">
    <ContentControl Content={StaticResource SharedUC1UserControl}" />
  </DataTemplate>
  <DataTemplate DataType="{x:Type vm:UC2ViewModel}">
    <ContentControl Content={StaticResource SharedUC2UserControl}" />
  </DataTemplate>
</Window.Resources>

另一种解决方案是创建一个控件来管理内容主机并生成/回收实际的数据容器(您的控件),就像ListBox所做的那样。这将给予你更多的灵活性。

相关问题