对于view / viewmodel,我有以下(浓缩的)silverlight xaml:
<UserControl x:Class=MyView>
<UserControl.Resources>
<MyViewModel x:Name="MyViewModel"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource MyViewModel}}">
<UserControl>
希望大家看起来很熟悉。
但是,我想创建这个相同视图用户控件的2个实例,但是要将参数传递给视图模型,以允许我根据我传递给视图模型的属性略微不同的视图模型数据。类似的东西:
<UserControl x:Class=MyView>
<UserControl.Resources>
<MyViewModel x:Name="MyViewModel" Filter="Some value set at a higher level"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource MyViewModel}}">
<UserControl>
问题是我无法在用户控件中硬编码Filter参数,但需要将其设置在更高级别。有没有办法通过绑定从更高的位置获取过滤器参数,以及语法是什么样的。我希望以下内容:
直接来自父母:
<MyView>
<MyView.ViewModel Filter="All">
</MyView>
<MyView>
<MyView.ViewModel Filter="Some">
</MyView>
或者从用户控件向上看,例如:
<UserControl.Resources>
<MyViewModel x:Name="MyViewModel" Filter="{Binding FilterTypeFromDataContextHigherUpTheTree}"/>
</UserControl.Resources>
但我不知道是否可以直接从父级引用静态资源视图模型来设置属性,或者语法是什么样的。
我也不知道是否有更简单的方法可以做到这一点,因为我怀疑我的方法不是很优雅。
真正的问题是我如何将参数传递给静态资源的视图模型
答案 0 :(得分:1)
虽然可以将ViewModel存储为资源,但我们通常会将ViewModel设置为视图的DataContext。然后,如果有人需要通过 View访问ViewModel ,他们只需将DataContext转换为正确的ViewModel类型并直接访问它的属性。
如果您想要使用过滤器的Binding路线,您有几个选择。如果子控件放在模板(或样式)中的父控件内,则可以将Bnding Soure设置为RelativeSource.TemplatedParent。您也可以使用ElementName,但仅当命名元素位于同一范围内时(在上面的示例中,命名元素必须位于MyView内部。)
我能想到的最后一个选项是在MyView上为过滤器公开DependencyProperty,然后设置ViewModel与该属性的绑定。这将有效地使过滤器冒泡,以便可以在MyView外部访问,但我根本不喜欢这种方法,因为它只是为了将它们传递给ViewModel而向View添加属性。这绝不应该发生。 ViewModel应该始终可以独立于View访问,这就是我建议通过DataContext属性(推断)或通过专门用于ViewModel(显式)的自定义属性公开它的原因。
答案 1 :(得分:0)
我有时会使用我的ViewModel(例如,将它们实例化为资源)。当我这样做时,我的VM会扩展DependencyObject,原因我稍后会详细说明。
我建议您将它们移动到app.xaml
并将它们定义为应用程序的资源,作为应用程序的资源,每个人都可以使用它们。那样你就可以
<UserControl
DataContext="{StaticResource MyViewModel}" />
此外,您可以将ViewModel的属性绑定在一起。这就是我扩展DependencyObject的原因。
当然,这会限制您使用MyViewModel的单个实例,这可能适用于您的情况,也可能不适用。如果它不起作用,我将定义一个包含共享数据的ViewModel,然后通过静态资源绑定到它,就像在“向上看”的例子中一样。