1

我有一个窗口和一个用户控件。UserControl 创建自己的视图模型,如下所示:

<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 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 的视图模型具有对象类型的可公开设置的属性。通过 DataContext 绑定,我期望一旦创建 UserControl3,其 DataContext 的值(这是对其视图模型的引用)将被分配给窗口视图模型上的 UserControl3Vm 属性。

实际发生的是 Window.UserControl3Vm 属性设置器以 null 值调用。

为什么会发生这种情况,实现我的想法的最佳方法是什么?

我知道将 UserControl 的 viewmodel 实例化为 Window 的 viewmodel 上的属性并让 UserControl 简单地绑定到它会更容易,(这也可以最大限度地减少视图与其视图模型的耦合)。但是在我工作的地方,它们有点疯狂,并且更喜欢先查看 MVVM 而不是先查看视图模型,所以我正在寻找最解耦的方法,以使视图模型在视图模型由它们的视图创建时有效地协作。

4

2 回答 2

2

我认为在OneWayToSource没有一些代码隐藏的情况下使用绑定是行不通的。

最初,您UserControl.DataContext被设置为 的实例UserControl3vm,但是您将替换UserControl3vm为 Binding,因此您的原始UserControl3vm文件不再在任何地方引用。

要使OneWayToSource绑定起作用,您必须首先将 设置DataContextOneWayToSource绑定,然后将绑定的 Source 设置为UserControl3vmUserControl 内部的新实例。

如果我没记错的话,您可以使用BindingOperations.GetBindingExpression获取绑定,并更新它的DataItem属性。您不能简单地设置,UserControl.DataContext因为它会覆盖您的OneWayToSource绑定。

Loaded就我个人而言,我会在事件背后的代码中做到这一点

如果他们坚持 View-First MVVM,那么 View 正在控制应用程序流,我看不出有任何理由将应用程序逻辑排除在 View 的代码隐藏之外。

所以只需在 Loaded 事件中设置你的Window.DataContext.UserControl3Vm属性:)UserControl3.DataContext

<Window x:Name="MyWindow"
        Loaded="MyWindow_Loaded" 
        ... >
    <StackPanel>
        <local:UserControl3 x:Name="MyUserControl" />
    </StackPanel>
</Window>

void MyWindow_Loaded(object sender, EventArgs e)
{
    ((MainWindowVm)MyWindow.DataContext).UserControl3Vm 
        = MyUserControl.DataContext;
}
于 2013-01-09T15:18:50.960 回答
0

这可以在 XAML 中使用一些解决方法(破解DataContext对主机元素的访问)。这里提到了该方法。它使用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>
于 2013-01-10T03:31:32.610 回答