首先,首先是一些背景。如果您熟悉该问题,请跳至BindingExpression
部分。这是我在WPF中的第一个主要项目,所以我对MVVM模式还很陌生。 Here是我发现的唯一一个类似的问题,其黯淡的回答并不能让我感到非常兴奋。
我正在/正在构建一个.NET 3.5 WPF应用程序,而我正在使用MVVM(自己实现,没有框架)。在此范围内,我有一些Views
和ViewModels
。它们分别位于主ApplicationView
和ApplicationViewModel
内。
我更改视图的方式是使用ApplicationView
中的XAML DataTemplate元素,如下所示:
<DataTemplate DataType="{x:Type viewmodels:InitViewModel}">
<views:InitView />
</DataTemplate>
然后在主体中我有一个ContentControl,它绑定到ApplicationViewModel
<ContentControl Content="{Binding CurrentPageViewModel}"/>
当我运行应用程序时,所有这些似乎都能正常工作,并完全符合预期。但是,当我在运行后查看Debug输出时,我会收到很多BindingExpression
错误。
这是一个例子。我的SplashText
中有一个属性InitViewModel
。这绑定到初始屏幕(InitView
)中的文本块。当启动画面结束并切换视图模型时,我得到以下内容:
System.Windows.Data Error: 39 : BindingExpression path error: 'SplashText' property not found on 'object' ''MainMenuViewModel' (HashCode=680171)'. BindingExpression:Path=SplashText; DataItem='MainMenuViewModel' (HashCode=680171); target element is 'TextBox' (Name='FeedBackBox'); target property is 'Text' (type 'String')
我理解这是因为绑定仍然存在,但DataContext的CurrentPageViewModel属性已更改。所以我想知道的是:
提前致谢,并为整体问题道歉。
编辑03/09/13 - 感谢Jehof,Francesco De Lisi和Faster Solutions指出将子视图datacontext设置为{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}
是没有意义的,因为ContentControl会处理datacontext。
答案 0 :(得分:2)
您的具体示例在.NET 4.5中无法重现,这可能意味着Microsoft已经解决了此问题。
然而,当Content和ContentTemplate都是数据绑定时,存在类似的问题。我将解决这个问题,如果有人还在使用它,它也可能解决.NET 3.5中的问题。例如:
<ContentControl Content="{Binding Content}" ContentTemplate="{Binding Template}" />
当ContentTemplate由DataTrigger确定时:
<ContentControl Content="{Binding Content}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Choice}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateA}" />
</DataTrigger>
<DataTrigger Binding="{Binding Choice}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateB}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
在这两种情况下,都会遇到类似于观察到的OP的绑定错误。
这里的技巧是确保以正确的顺序执行对Content和ContentTemplate的更改,以防止绑定错误。我写了DelayedContentControl,确保Content和ContentTemplate能够以正确的顺序同时更改。
<jc:DelayedContentControl Content="{Binding Content}" ContentTemplate="{Binding Template}">
同样适用于DataTrigger案例。
您可以从我的开源JungleControls library获取DelayedContentControl。
答案 1 :(得分:1)
当您的财产属于另一个生成错误的DataContext
属性时,MainMenuViewModel
似乎转到ViewModel
。
启动画面前后的CurrentPageViewModel
值会在切换视图时失去Binding
。
问题归结为DataContext="{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
事实上,CurrentPageViewModel = InitViewModel
当你的应用程序启动时,问题是每个View
都有相同的DataContext
(即InitViewModel
,但我确定ViewModels
没有满足视图绑定的整个所需属性池。
一个例子要理解:
ViewX
与PropertyX
绑定,在ViewModelX
中进行管理。
ViewY
具有PropertyY
的约束力,在ViewModelY
中进行管理。
两者都有DataContext = CurrentViewModel
。
在启动CurrentViewModel = ViewModelX
上,ViewX和ViewY都有 DataContext = ViewModelX 。但这是错误!并且可能会产生错误。
我通常做的是在View类中使用相应的View Model设置DataContext(如果您愿意,使用cs或XAML)以确保它适合。然后,在需要时,我每次切换页面时都会调用刷新方法来更新我的值。如果您有共享属性,请考虑使用模型来集中您的信息(和值)。
来自http://wildermuth.com/images/mvvm_layout.png
的示例图片
显然,视图是由MainWindow包装的控件。
希望很清楚。
答案 2 :(得分:0)
让我们按顺序回答您的问题:
我还建议看一个框架。像MVVM Light这样轻量级的东西可以通过很少的集成为您解决一系列问题。它的ViewModelLocator模式也可以做你正在做的事情,但没有副作用,并提供了一大堆清理选项。
答案 3 :(得分:0)
您可以在Views
中省略DataContext的绑定DataContext="{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
因为DataContext
的{{1}}是View
的{{1}},并且由DataContext
- 属性的绑定设置。
因此,当您的媒体资源ContentControl
设置为Content
时,CurrentPageViewModel
会将InitViewModel
用作ContentControl
并使用InitViewModel
作为DataContext
,它将自己的DataContext设置为InitView的DataContext。