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

发布于 2024-08-16 22:56:22 字数 1426 浏览 2 评论 0原文

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

我有一个视图,其中包含自定义控件。这些自定义控件实际上也是视图,并且有 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 此处 但不确定它是如何工作的以及是否是我想要的 -

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

非常感谢任何帮助。

詹姆斯

I'm fairly new to the Silverlight and the MVVM / Prism pattern so this may be a stupid question.

I have a View which has custom controls within it. These custom controls are actually Views too and have ViewModels to drive them.

Currently to add these 'child' Views to the View I'm using (see Fig.1) and then in the ViewModel I have an Initialise() method which resolves the child View and injects it (see Fig.2).

Fig.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>

Fig.2

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

My question is do I have to do this for every control I want to add? I understand why it works this way but it seems like quite a bit of code and also I need to keep track of all the region names and ensure I don't have any clashes etc. Is there a simpler way of doing this without regions and just in XAML?

I've seen a snippet of XAML on StackOverflow here but not sure how it works and if it's what I want -

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

Any help is much appreciated.

James

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蝶…霜飞 2024-08-23 22:56:22

澄清后编辑:

看来您根本不想使用 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()));
     }
}

这是您的 View(看,没有 RegionManager!):

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

区域管理器有点试图为您提供我在这里写的所有内容,加上很多可扩展点,但如果您不喜欢 RegionManager 或您发现由于某种原因它不符合您的需求,这就是您在没有它的 Silverlight 中执行此操作的方式。


进一步编辑:

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

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

<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 来显示这些视图。

Edit after clarification:

It appears you don't want to use RegionManager at all, which is fine. What I would suggest then is this:

Create an interface for your Modules to use to register view creation methods:

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

Your modules will use this like this:

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;
          });
     }
}

Then in your shell, you first implement the view registry (this is a simplification... you'd probably want something more robust)

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);
     }
}

And lastly, here's how your shell would show that stuff. Here's its ViewModel first:

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

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

And here's your View (look ma, no RegionManager!):

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

The region manager sort of attempts to give you everything I've written here, plus a lot of extensibility points, but if you don't like RegionManager or you find it doesn't fit your needs for some reason, this is how you would do this in Silverlight without it.


Further Edits:

After some more commentary from the OP, I think I understand that the OP just wants to show a view within another view without having to use RegionManager. It appears the OP is using RegionManager to show every view on the screen, which is probably overkill.

The scenario I was given included an Address View and associated ViewModel being used from a different parent control. This is what I do (whether right or wrong):

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

And here's the parent view's viewModel:

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

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

That's it. This prevents you from having to work too hard to show these views.

RegionManager is really appropriate for decoupling the parent container view from the subview, but if both of these live in the same place (same module / assembly) there is no reason to use RegionManager to show these views.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文