Prism MVVM - 将子视图添加到父视图而不使用区域和注入,只是XAML

时间:2010-01-07 11:19:10

标签: c# silverlight mvvm controls prism

我对Silverlight和MVVM / Prism模式相当新,所以这可能是一个愚蠢的问题。

我有一个View,里面有自定义控件。这些自定义控件实际上也是视图,并且有ViewModel来驱动它们。

目前要将这些“子”视图添加到我正在使用的视图中(参见图1),然后在ViewModel中我有一个Initialise()方法,该方法解析子视图并将其注入(参见图2)

图1

<UserControl
x:Class="ProjectA.Module.Screens.Views.PlatformScreenView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
>
<Grid x:Name="LayoutRoot">
    <ContentControl
        Regions:RegionManager.RegionName="FeaturesSelectionControl"
        />
</Grid>

图2

public void Initialise()
{
    IRegion featuresRegion = _regionManager.Regions["FeaturesSelectionControl"];
    featuresRegion.Add(_container.Resolve<IFeatureSelectionControlViewModel>().View);
}

我的问题是我是否必须为每个要添加的控件执行此操作?我明白为什么它以这种方式工作,但它似乎是相当多的代码,我需要跟踪所有的区域名称,并确保我没有任何冲突等。是否有一个更简单的方法这样做没有区域和只是在XAML?

我在StackOverflow here上看到了一段XAML,但不确定它是如何工作的,如果它是我想要的 -

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

非常感谢任何帮助。

詹姆斯

1 个答案:

答案 0 :(得分:1)

澄清后编辑:

看起来你根本不想使用RegionManager,这很好。我建议的是:

为模块创建一个接口,用于注册视图创建方法:

public interface IViewRegistry
{
     void RegisterMainView(Func<object> ViewCreationDelegate);
}

您的模块将使用如下:

public MyModule : IModule
{
     IViewRegistry _registry;
     public MyModule(IViewRegistry registry)
     {
          _registry = registry;
     }

     public void Initialize()
     {
          _registry.RegisterMainView(() =>
          {
               var vm = new MyViewModel();
               var view = new MyView();
               var view.DataContext = vm;
               return view;
          });
     }
}

然后在你的shell中,你首先实现了视图注册表(这是一个简化......你可能想要更强大的东西)

public ViewRegistry : IViewRegistry
{
     public static List<Func<object>> ViewFactories
     {
           get { return _viewFactories; }
     }
     static List<Func<object>> _viewFactories = new List<Func<object>>();
     public void RegisterMainView(Func<object> viewFactory)
     {
          _viewFactories.Add(viewFactory);
     }
}

最后,这是你的shell如何显示这些东西。首先是它的ViewModel:

public ShellViewModel : ViewModel
{
     public ObservableCollection<object> MainViews
     {
          ...
     }

     public ShellViewModel()
     {
          MainViews = new ObservableCollection<object>(ViewRegistry.Select(factory => factory()));
     }
}

这是你的视图(看看ma,没有RegionManager!):

<UserControl ...>
   <Grid>
     <ItemsControl ItemsSource="{Binding MainViews}" />
   </Grid>
</UserControl>

区域经理试图给你我在这里写的所有东西,加上很多可扩展点,但是如果你不喜欢RegionManager,或者你发现它不符合你的需要,那就是如果没有它,你将如何在Silverlight中做到这一点。


进一步修改:

在OP的一些更多评论之后,我想我明白OP只是想在另一个视图中显示视图而不必使用RegionManager。看来OP正在使用RegionManager在屏幕上显示每个视图,这可能有点过分。

我给出的场景包括一个地址视图和从不同父控件使用的相关ViewModel。这就是我所做的(无论是对还是错):

<UserControl x:Class="Views.MyParentView" ...>
<StackPanel>
     <TextBlock>Blah blah blah some other stuff... blah blah</TextBlock>
     <myViews:AddressView DataContext="{Binding AddressVM}" />
</StackPanel>
</UserControl>

这是父视图的viewModel:

public ParentViewModel : ViewModel
{
     public AddressViewModel AddressVM
     {
          ...
     }

     public ParentViewModel()
     {
          AddressVM = new AddressViewModel();
     }
}

就是这样。这可以防止您不必太努力地显示这些视图。

RegionManager非常适合将父容器视图与子视图分离,但如果它们都位于同一位置(相同的模块/程序集),则没有理由使用RegionManager来显示这些视图。