2013-01-09 28 views
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的viewmodel有一個可公開設置的object類型屬性。通過DataContext綁定,我期望在創建UserControl3後,其DataContext(它是對其視圖模型的引用)的值將被分配給Window的viewmodel上的UserControl3Vm屬性。

實際發生的事情是Window.UserControl3Vm屬性設置器被調用的值爲null。

爲什麼會發生這種情況,實現我的想法的最佳方法是什麼?

我知道將UserControl的視圖模型實例化爲Window視圖模型的一個屬性並讓UserControl簡單地綁定到該視圖上(並且這也將視圖與視圖模型的耦合最小化) 。但是在我工作的地方,他們有點瘋狂,我更喜歡首先查看第一個MVVM,而不是第一個查看模型,所以我正在尋找最分離的方式,以便在視圖模型由其視圖創建時使視圖模型有效地進行協作。

回答

2

我不認爲它會工作,使用沒有一些代碼隱藏的OneWayToSource綁定。

最初,你UserControl.DataContext設置爲UserControl3vm一個實例,但是你是一個綁定更換UserControl3vm,所以你的原始UserControl3vm不再在任何地方引用。

對於OneWayToSource綁定工作,你必須首先設置DataContextOneWayToSource結合,然後從你的用戶控件中設置綁定的源向UserControl3vm一個新的實例。

如果我沒有記錯,可以使用BindingOperations.GetBindingExpression獲取綁定,並更新它的DataItem屬性。您不能簡單地設置UserControl.DataContext,因爲它會覆蓋您的OneWayToSource綁定。

個人而言,我會做它在代碼背後的Loaded事件

如果他們上查看,首先MVVM堅持,然後在查看被控制應用程序的流程,我看不出有任何理由您應該將應用程序邏輯放在View的代碼隱藏之外。

所以,只要將Window.DataContext.UserControl3Vm屬性UserControl3.DataContext在Loaded事件:)

<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; 
} 
+1

這是一些討厭的耦合對那裏發生的。 UserControl視圖必須知道託管它的視圖使用的視圖模型的具體類型。如果UserControl由各種不同的視圖託管會怎麼樣?然後,它需要調用其擁有的視圖的類型,以便能夠將其視圖模型引用分配給其擁有者的視圖模型。 – Neutrino

+0

@Neutrino Loaded事件應該放在'Window'後面的代碼中,而不是'UserControl',所以它只需要引用它自己的ViewModel的數據類型。我會更新代碼示例以使其更易於查看。 – Rachel

+0

對不起,我一直在昏暗。是的,這工作得很好。我甚至不需要使用Loaded事件,我可以在窗口構造函數中調用InitializeComponent之後立即執行此操作。 – Neutrino

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> 
相關問題