在WPF/MVVM中动态更改UserControl内容的方法

3
我正在尝试创建一个多部分结果查看器。当您的批处理作业完成时,您将能够双击打开此屏幕,其中包含有关刚刚运行的批处理作业的基本数据的顶部部分(屏幕的30%,全宽),然后下部的70%将包括一个左对齐的列表框(宽度的20%)和占据其余80%宽度的详细资料窗格。
我希望它的行为方式是,当您在左侧列表框中选择子结果时,右侧面板将填充子结果的详细信息。由于它将变得复杂并且需要可伸缩性,因此我想将每个子结果详细显示面板实现为UserControl。
父ViewModel包含一个IDictionary<Enum.ResultType,IResultPanel> - 列表框将从该字典的键中填充,并且当您选择选项时,它将从字典中提取IResultPanel对象,该对象将是用户控件。以下是一个示例片段。
public partial class SimpleCalcInfoResult : UserControl, IResultPanel
    {
        private SimpleCalcInfoResultViewModel _viewModel;

        public SimpleCalcInfoResult(SimpleCalcInfoResultViewModel viewModel)
        {
            InitializeComponent();
            _viewModel = viewModel;
        }
    }

IResultPanel 接口是一个空接口,仅用于方便具有公共类型的字典,因为我认为拥有 UserControl 字典太广泛了。

我面临的问题是我无法弄清楚在父控件中使用什么 XAML 来具有可更改的 UserControl 面板。显然,您可以拥有

<local:MyControl> ... </local:MyControl>

作为一个硬编码的用户控件,但是我该如何有一部分XAML可以让我根据选择哪个列表框项来显示哪个用户控件?


请了解WPF模板化,特别是DataTemplateSelectors(http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector)和DataTemplates(http://msdn.microsoft.com/en-us/library/ms742521.aspx),以及DataType。 - DenisPostu
1个回答

16

使用WPF很容易实现这一点。但是在使用MVVM时,我们“操作”数据而不是UI控件。考虑到这一点,首先在Application.Resources部分为每个自定义Panel控件声明一个DataTemplate

<DataTemplate DataType="{x:Type ViewModels:SimpleCalcInfoResultViewModel}">
    <Views:SimpleCalcInfoResult />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
    <Views:MainView />
</DataTemplate>

现在你只需要使用 ContentControl 在你的右下角显示相关的视图模型:

<ContentControl Content="{Binding ViewModel}" />

最后,向您的父视图模型添加一个类型为IResultPanel的属性,名为ViewModel

private IResultPanel viewModel = new FirstViewModel();

public IResultPanel ViewModel
{
    get { return viewModel; }
    set { if (viewModel != value) { viewModel = value; NotifyPropertyChanged("ViewModel"); } }
}

现在您只需要将此属性设置为不同的值,即可在应用程序中显示不同的 Panel

ViewModel = new SimpleCalcInfoResultViewModel();

非常感谢,回答非常全面。所以我想知道,我是否仍然需要创建和定义一个UserControl xaml类,例如SimpleCalcInfoResult,并在其中包含该结果类型的所有显示逻辑,在数据模板中只需指定一行即可,即该UserControl的实例创建? - NZJames
还有一个问题,我的 SimpleCalcInfoResult UserControl 有一个构造函数,它接受一个 SimpleCalcInfoResultViewModel 对象作为参数。我该如何编写上面的数据模板来创建用户控件,并将视图模型对象作为第一个参数传递给构造函数? - NZJames
是的,对于你的第一个评论...这就是你需要做的全部。有了这些定义的DataTemplate,无论框架在哪里看到你的视图模型的实例,它都会显示指定的UserControl。你的第二个评论似乎有点混淆...你的构造函数以视图模型作为参数,但是使用这种方法,你不需要这样做...DataTemplate代替设置DataContext。你仍然可以通过将其DataContext转换为正确类型的视图模型来从UserControl代码后台访问视图模型:ThisViewModel vm = (ThisViewModel)DataContext; - Sheridan
抱歉回复晚了。关于第二部分,我尝试了你说的方法,但在SimpleCalcInfoResult视图的构造函数中,我尝试将DataContext转换为VM类型,但是View的DataContext为空。我错过了什么重要的步骤吗? - NZJames
构造函数被调用时,它可能尚未被设置。尝试使用“Window.Loaded”事件,将您的代码放在该处理程序中。 - Sheridan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接