我有一个Window和一个UserControl。 UserControl创建自己的viewmodel,如下所示:
<UserControl x:Class="UiInteraction.UserControl3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UiInteraction"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:UserControl3Vm/>
</UserControl.DataContext>
<StackPanel>
<TextBlock Text="{Binding String1}"/>
</StackPanel>
</UserControl>
当Window实例化UserControl时,我希望Window的viewmodel能够检索UserControl的viewmodel。
<Window x:Class="UiInteraction.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UiInteraction"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowVm/>
</Window.DataContext>
<StackPanel>
<local:UserControl3 DataContext="{Binding UserControl3Vm, Mode=OneWayToSource}"/>
</StackPanel>
</Window>
Window的viewmodel具有object类型的公共可设置属性。使用DataContext绑定,我期望一旦创建UserControl3,其DataContext的值(它是对其viewmodel的引用)将被分配给Window的viewmodel上的UserControl3Vm属性。
实际发生的是使用null值调用Window.UserControl3Vm属性setter。
为什么会发生这种情况,实现我的想法的最佳途径是什么?
我知道将UserControl的viewmodel实例化为Window的viewmodel上的属性并让UserControl简单地绑定到它上(并且这也会最小化视图与其viewmodel的耦合)会更容易。但是在我工作的地方他们有点疯狂并且首先选择查看第一个MVVM而不是viewmodel,所以我正在寻找最分离的方式来使viewmodel在视图模型由视图创建时有效地进行协作。
答案 0 :(得分:2)
我不认为在没有代码隐藏的情况下使用OneWayToSource
绑定会起作用。
最初,您的UserControl.DataContext
设置为UserControl3vm
的实例,但是您要用绑定替换UserControl3vm
,因此您的原始UserControl3vm
不再在任何地方引用。
要使OneWayToSource
绑定起作用,您必须先将DataContext
设置为OneWayToSource
绑定,然后将绑定的Source设置为{{1}的新实例来自UserControl内部。
如果我没记错,您可以使用BindingOperations.GetBindingExpression获取绑定,并更新它的DataItem属性。您不能简单地设置UserControl3vm
,因为它会覆盖您的UserControl.DataContext
绑定。
就个人而言,我只会在OneWayToSource
事件背后的代码中执行此操作
如果他们坚持使用View-First MVVM,那么View正在控制应用程序流程,我认为你没有任何理由将应用程序逻辑保留在View的代码隐藏之外。
所以只需在Loaded事件中将Loaded
属性设置为Window.DataContext.UserControl3Vm
:)
UserControl3.DataContext
答案 1 :(得分:0)
这可以在XAML中使用一些解决方法(破解DataContext
主机元素的访问权限)。提到了这种方法here。它使用Freezables。
XAML
<Window x:Class="VM2VMBindingInXaml.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vw="clr-namespace:VM2VMBindingInXaml.View"
xmlns:vm="clr-namespace:VM2VMBindingInXaml.ViewModel"
Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
<vm:UserControl1ViewModel x:Key="childVM"></vm:UserControl1ViewModel>
<vm:DataResource x:Key="childVmBinding" BindingTarget="{Binding ElementName=child, Path=DataContext}"/>
</Window.Resources>
<Window.DataContext>
<vm:MainWindowViewModel x:Name="mainViewModel" >
<vm:MainWindowViewModel.ChildViewModel>
<vm:DataResourceBinding DataResource="{StaticResource childVmBinding}">
</vm:DataResourceBinding>
</vm:MainWindowViewModel.ChildViewModel>
</vm:MainWindowViewModel>
</Window.DataContext>
<Grid>
<vw:UserControl1 x:Name="child" DataContext="{Binding Source={StaticResource ResourceKey=childVM}}">
</vw:UserControl1>
</Grid>
</Window>