UWP 应用程序:插入/删除用户控件 MVVM 方式

UWP app: insert / remove user control MVVM way

我目前正在学习 UWP,试图将旧的 Win32 移植到新平台。我正在使用 Template10,到目前为止一切运行良好,除了我对如何实现下面的问题有点困惑。

问题:在页面中,我必须不断地根据视图模型删除和插入用户控件属性。用户控件相当复杂,而且它们的外观和行为都不同。想象一个带有后退和下一步按钮的向导。每次点击我都必须删除旧内容并插入一个具有完全不同视图模型的新内容。

问题:以 MVVM 方式实现它的推荐方法是什么?

目前,我唯一的想法是从页面的视图模型发送消息并在页面代码后面订阅消息,在那里我可以创建所需的组件并将其动态插入页面(删除旧的之后一个).

在 MyPageViewModel 中:

public IComponentViewModel CurrentComponent {get; set;}
...
public DelegateCommand NextItemCommand = new DelegateCommand(() =>
{
    var evt = App.EventAggregator.GetEvent<ItemChangedMessage>();
    evt.Publish(CurrentComponent);
});

在MyPage.xaml.cs代码后面

public MyPage()
{
    InitializeComponent();
    var evt = App.EventAggregator.GetEvent<ItemChangedMessage>();
    evt.Subscribe(OnItemChanged);
}

private void OnItemChanged(IComponentViewModel viewModel)
{
    switch (viewModel.Type)
    {
        case 1:
            // create the new user control and insert it in the container
            var component = new TypeOneComponent();
            component.DataContext = (TypeOneCompoentViewModel)viewModel;
            // ...
        case 2:
            ...
     }
}

虽然不确定这是最好的方法。

我通常使用 ItemsControl。这允许您拥有一个通用项目模板和一个项目特定模板(如果需要),并且您可以通过绑定到 ItemsSource 随意添加/删除项目。

在您的向导示例中,您可以将主向导容器设为一次仅显示一个项目的 ItemsControl,而页面将是 "item"。与 MVVM 的区别在于你不添加子 controls,你添加 data 然后指定一个模板来渲染它。所以你的项目将是简单的数据绑定 poco 对象。

对于您的实际示例,我想您可以将子控件添加到 ItemsControl,它们会自动呈现,甚至无需使用模板,因为 ContentPresenter 知道如何呈现控件。我仍然会仅使用数据 类,因为 MVVM 的租户之一是将数据与 UI 分开。因此,您的子项目将是一个模型,而您的项目特定模板将是绑定到项目数据的 UI 布局。

我最近一直在考虑使用向导方法。在我看来,带有重新模板化 left/right 按钮的 FlipView 是最简单的方法。我的 WizardViewModel 会有几个子视图模型;类似于 Page1ViewModel、Page2ViewModel 等。我 强烈地 认为每个页面视图模型都会有一个专用的 UserControl 所以 UI 可以是唯一的但不是动态的 - 我认为设计反对动态 UI,同时拥抱自适应 UI - 这完全是一个不同的概念。

伪代码可能如下所示:

public interface IWizardPage { }

public class Page1ViewModel : ViewModelBase, IWizardPage { }
public class Page2ViewModel : ViewModelBase, IWizardPage { }
public class Page3ViewModel : ViewModelBase, IWizardPage { }

public class MainPageViewModel : ViewModelBase
{
    public IWizardPage CurrentPage { get; set; }
    public IWizardPage Page1ViewModel { get; set; }
    public IWizardPage Page2ViewModel { get; set; }
    public IWizardPage Page3ViewModel { get; set; }
}

还有这个:

<FlipView Template="{StaticResource WizardFlipView}" 
            SelectedItem="{Binding CurrentPage, Mode=TwoWay}">
    <Page1UserControl DataContext="{Binding Page1ViewModel}" />
    <Page2UserControl DataContext="{Binding Page2ViewModel}" />
    <Page3UserControl DataContext="{Binding Page3ViewModel}" />
</FlipView>

这只是一个建议。但是要回答您的问题,这非常适合 MVVM 模式。我还认为这将使您变得非常灵活,而不会变得过于动态以至于维护非常耗时。有很多方法可以做向导。我认为这将是一个很好的解决方案,适用于 MVVM 模式,适用于模板 10。

祝你好运。