【问题标题】:How to get my original ViewModel?如何获得我原来的 ViewModel?
【发布时间】:2016-06-20 16:53:06
【问题描述】:

我创建了一个以 ViewModelA() 作为其 ViewModel 的用户控件,然后在我的视图中,有一个 StackPanel 使用 ViewModelA.Data 作为 DataContext。

我的问题在这个 StackPanel 内部,我有一个按钮需要在 ViewModelA() 中实现我创建的 ICommand。我该怎么做?

有类似<Button DataContext="DataContext.Parent" /> 之类的吗?

这是我实现 ViewModel 和 View 的方式:

App.xaml

<DataTemplate DataType="{x:Type vm:ViewModelA}">
    <vw:ViewA />
</DataTemplate>

ViewA.xaml(堆栈面板内的按钮应该实现 ICommand)

<StackPanel x:Name="RightPaneDetails"
            Grid.Column="1"
            Margin="15,0,0,30"
            DataContext="{Binding Data}">
    <!-- Some controls goes here that binds to ViewModelA.Data properties -->
    <StackPanel Orientation="Horizontal">
        <Button DataContext={Binding} Command="{Binding LookupCommand}" /> <!-- This button should implement the ViewModelA.LookupCommand -->
    </StackPanel>
</StackPanel>

TIA

PS,ViewModelA.Data 是我的模型。

【问题讨论】:

  • DataContext 是沿可视化树继承的,根本不需要指定 DataContext。删除 ViewA 中的所有 DataContext,所有控件都应默认其 DataContext 回 ViewModelA。
  • 是的,我明白了。但是我的控件(文本框和标签)受 ViewModelA.Data 属性的限制...如果我删除 &lt;StackPanel DataContext="{Binding Data}"&gt; ...... &lt;/StackPanel&gt; 然后将所有绑定控件作为&lt;TextBox Text="{Binding Data.LastName}" /&gt; 放入我的所有绑定控件会很丑吗?
  • 在没有 DataContext 部分的情况下尝试 AnjumSKhan 的答案。
  • @Jai - 我试过了,但还是不行。 Button 仍在查看 Data 而不是 ViewModelA...
  • @Jai - 不用等待......它成功了!!!谢谢!

标签: wpf mvvm


【解决方案1】:

您在 UC 中似乎已将 DataContext 设置为 ViewModelA。所以,你可以使用

&lt;Button DataContext={Binding} Command="{Binding DataContext.LookupCommand, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}}" /&gt;

也可以写成:

&lt;Button DataContext={Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor} } Command="{Binding LookupCommand}" /&gt;

【讨论】:

  • 我对您的 UserControl 的 DataContext 做了假设。显示完整的 XAML。
  • 使用 Snoop 或 Live-Property-Explorer (VS2015) 深入了解控件的 DataContext
  • @AnjumSKhan - 没什么特别的。只是“数据”是我的 ViewModelA 中的模型。当我尝试将按钮放在 StackPanel 之外时,LookupCommand 起作用。
  • @AnjumSKhan - 经过几次尝试,它可以工作。我不知道为什么,但我确定我重新启动了 VS,然后 Jai(来自有问题的 cmets)建议尝试你的,我在没有 DataContext="{Binding}" 的情况下再次尝试了你的答案,它奏效了!谢谢!
  • @JackFrost 说真的,我认为DataContext部分不会有任何影响,因为当我们使用RelativeSource时,绑定引擎根本不会打扰DataContext,不确定这里发生了什么。也许 AnjumSKhan 可以解释原因;他在这里知识渊博。
【解决方案2】:

虽然@AnjumSKhan 的解决方案是正确的,但我想提出替代解决方案:

<StackPanel x:Name="RightPaneDetails"> <!-- do not set bind datacontext here -->

    <!-- Some controls goes here that binds to ViewModelA.Data properties, e.g: -->
    <TextBlock Text="{Binding Data.SomeProperty}" />
    <!-- If there too many elements bound to Data, you can group them in stackpanel -->


    <StackPanel Orientation="Horizontal">
        <!-- This button is databound to ViewModelA.LookupCommand 
             DataContext doesn't have to be set, since it's inherited from parent. Actually entire stackpanel is redundant here-->
        <Button Command="{Binding LookupCommand}" /> 
    </StackPanel>
</StackPanel>

如您所见,我只是避免在父 RightPaneDetails 上设置 DataContext,因此孩子可以轻松访问 ViewModelA.Data 的属性(TextBlock)和 ViewModelA 的属性(按钮)


其他几点注意事项:
  1. 注意,不是

    RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor} 
    

    你可以只写

    RelativeSource={RelativeSource AncestorType=UserControl}
    
  2. RelativeSource 的替代解决方案是 ElementName:

    <StackPanel x:Name="Root">
      <StackPanel DataContext="{Binding Data}">
        <Button Command="{Binding DataContext.LookupCommand, ElementName=Root}" />
    

    我更喜欢这个,因为在编译时会检查“根”元素的存在并且它更具可读性。

  3. 避免在同一元素上绑定 DataContext 和另一个 Property,例如:

    <Button DataContext="{Binding....}" Command="{Binding ...}" />
    

    无法保证首先评估哪个绑定。但是,您可以将 IsAsyc=True 设置为第二个绑定 Command={Binding ..., IsAsync=True},以确保它的评估时间晚于非异步绑定

【讨论】:

  • 我也在考虑这个问题。但显然 OP 觉得这很难看。对于我自己的个人喜好,我也会选择这种方法。当您开始在不同部分分配 DataContext 时,绑定变得更加复杂。我希望整个 View 使用继承的 DataContext,并在编写链式绑定路径时发挥更大的作用。
猜你喜欢
  • 2019-01-22
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多