快速回答和总结:
如您所见,您真正想要的是从 XAML 参数化您的 ViewModel。所以我的直觉是写一个附加行为来为你的视图模型提供传递参数的能力。更具体地说,想到的是我们想要一个 single 附加的 Behavior 类,我们可以指定 both (a) 我们想要哪个 ViewModel 和 (b) 该 ViewModel 的参数。为了在单个类中满足两个这两个愿望,同时尽可能地成为DRY,我认为使用“混合”行为是最简单的,因为混合行为不是静态类,因此它似乎更容易使用它们将两条相关信息一起传递。
解释:
首先快速免责声明:我没有使用过 MEFedMVVM 或 Prism(但我使用过其他 MVVM 库),所以我的回答使用了我最近学会使用的更通用的方法。因此,当您以“正常”方式使用事物(即自动连接 DataContext 等)时,这种方法不依赖 Prism 可能为您提供的任何“神奇”东西,所以让这种心态成为框架。
关于“常规”附加行为和“混合”行为之间差异的好文章,我喜欢this blog post。我不会在这里重复他的解释,但我注意到的关键是常规的附加行为似乎只依赖于单个条信息(即单个“参数”)来执行它的东西。如(来自博文):
<GridView local:ItemClickNavBehavior.Destination="Home" ...>
现在让我们根据您的情况来说明,如果您只使用 regular Attached Bahaviors,它会如何工作。您将编写一个附加行为类,将其称为“MyViewModel1Creator”,它会:
(1) 注册一个名为“Type”的附加属性,并且
(2) 包括一个“类型”的更改回调处理程序(在初始设置时也会调用它 - 请参阅链接博客文章中的“HookupBehavior”方法)。在此更改回调中,您将实例化“ViewModel1”并将“Type”附加属性的值传递给它。同样在此方法中,您可以处理任何其他必需品,例如为视图设置 DataContext 等。您可以使用第一个参数访问附加属性附加到的对象(在本例中为视图对象)回调处理程序(依赖对象参数)。
那么您对“MyViewModel1Creator”类的 Xaml 使用将如下所示:
<views:MyView x:Name="view1" MyBehaviors:MyViewModel1Creator.Type="X" />
<views:MyView x:Name="view2" MyBehaviors:MyViewModel1Creator.Type="Y" />
虽然这可行,但我发现这种方法有一个缺点(使用常规附加属性)。要使用这种方法,您必须为每个 ViewModel 创建一个单独的 Attached Behavior 类,这意味着如果您有 3 个 ViewModel(“ViewModel1”、“ViewModel2”、“ViewModel3”),那么您需要编写 3 个 Attached Behavior 类( “ViewModel1Creator”、“ViewModel2Creator”、“ViewModel3Creator”)。每个都将实例化其各自的 ViewModel(并公开一个“类型”附加属性,如上所示)。另一个缺点是似乎更难找到添加additional参数的方法。
与上述方法稍有不同,但 同样不足 就成为 DRY 而言,将是拥有一个类(称之为“MyViewModelCreator” - 没有“1”这个time) 包含几个附加属性,名称如“CreateViewModel_1_WithType”、“CreateViewModel_2_WithType”、“CreateViewModel_3_WithType”等。其用法如下所示:
<views:MyView x:Name="view1"
MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="X" />
<views:MyView x:Name="view2"
MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="Y" />
同样,这些方法不是很干,所以我们真的需要......
您将编写一个派生自类型化 Behavior 的类 - 对于您的视图,它可能是 Behavior<UserControl>,因此您的类标题可能类似于:
public class ViewModelSetupBehavior : Behavior<UserControl>。在本课程中,您将:(1) 注册任意数量的依赖属性,包括“类型”依赖属性和“ViewModelName”依赖属性,以及 (2) 您将覆盖OnAttached() 方法,您将在该方法中实例化由“ViewModelName”依赖属性的值指示的任何ViewModel,并将“Type”依赖属性的值传递给它。同样,这也是处理任何其他必需品的地方,例如为视图设置 DataContext 等。您可以使用 AssociatedObject 访问行为“附加到”的对象(在本例中为您的视图)属性。
这可以让你这样做:
<views:MyView x:Name="view1">
<i:Interaction.Behaviors>
<MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="X" SomeOtherParam="bla" />
</i:Interaction.Behaviors>
</views:MyView>
<views:MyView x:Name="view2">
<i:Interaction.Behaviors>
<MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="Y" />
</i:Interaction.Behaviors>
</views:MyView>
现在请注意,我们可以使用 single Behavior 类来创建 all 我们的 ViewModel,我们可以传入 several em> 参数来指示我们希望如何实例化 ViewModel。