WPF 绑定到父 DataContext

Posted

技术标签:

【中文标题】WPF 绑定到父 DataContext【英文标题】:WPF Binding to parent DataContext 【发布时间】:2012-11-05 02:56:27 【问题描述】:

我们有一个带有标准 MVVM 模式的 WPF 应用程序,利用 Cinch(以及 MefedMVVM)进行 View -> ViewModel 解析。这很好用,我可以将相关控件绑定到 ViewModel 上的属性。

在特定视图中,我们有一个 Infragistics XamGrid。此网格绑定到 ViewModel 上的 ObservableCollection,并显示相应的行。但是,然后我在此网格上有一个特定列,我试图将 TextBox 文本值绑定到父 DataContext 上的属性,而不是 ObservableCollection。此绑定失败。

我们在这里经历了几个选择,包括:

    使用 AncestorType 跟踪树并像这样绑定到父 UserControl 的 DataContext(从great answer 到这个问题,以及this one)...

    Binding Path=PathToProperty, RelativeSource=RelativeSource AncestorType=x:Type typeOfAncestor
    

    指定 ElementName 并尝试直接定位***控件。如果您想了解如何使用 ElementName,请联系 look here。

    使用在资源中为 UserControl 定义的“代理”FrameorkElement 尝试根据需要“传入”上下文。我们将元素定义如下,然后作为静态资源引用...

    <FrameworkElement x:Key="ProxyContext" DataContext="Binding Path=DataContext, RelativeSource=RelativeSource Self"></FrameworkElement>
    

在这种情况下,绑定会找到 FrameworkElement,但无法访问除此之外的任何内容(指定路径时)。

仔细阅读后,这很可能是由 Infragistics XamGrid 在树外构建列引起的。但是,即使是这种情况,至少选项 2 或 3 应该有效。

我们最后的想法是它与 V - VM 绑定有关,但即使使用 Snoop,我们还没有找到确切的问题。我绝不是 WPF 绑定方面的专家,所以任何指针都将不胜感激。

编辑:我从 Infragistics here 中找到了一些模板示例,我将尝试。

编辑 2:正如@Dtex 所指出的,模板是要走的路。这是与 XamGrid 一起使用的相关 sn-p:

<ig:GroupColumn Key="CurrentDate">
                <ig:GroupColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="Binding Path=DataContext.CurrentDateTest, RelativeSource=RelativeSource AncestorType=UserControl" />
                    </DataTemplate>
                </ig:GroupColumn.HeaderTemplate>
                <ig:GroupColumn.Columns>

我已将 XML 保持打开状态...您只需添加所需的列,然后关闭相关标签。

【问题讨论】:

“仔细阅读,这很可能是由 Infragistics XamGrid 在树外构建列引起的。但是,即使是这种情况,至少选项 2 或 3 应该可以工作” .实际上我认为这是不正确的,它们不在可视化树中,您无法引用任何内容,即使使用 ElementName 也是如此。例如,您可以通过定义 DataGridTemplateColumn 并在单元格模板中指定绑定来解决它 @Dtex 当然,这就是我的绑定/树知识限制让我慢下来的地方。我会尝试一个模板列,但如果你有一个例子,我会很感激。 只是 IMO,但 this 是我认为用户控件/自定义控件不应设置其DataContext 的原因。它破坏了消费者的东西! 请不要将答案放在问题中。您可以发布单独的答案帖子以分享您的解决方案。 【参考方案1】:

我不知道 XamGrid,但这就是我将使用标准 wpf DataGrid 做的事情:

<DataGrid>
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="Binding DataContext.MyProperty, RelativeSource=RelativeSource AncestorType=MyUserControl"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox Text="Binding DataContext.MyProperty, RelativeSource=RelativeSource AncestorType=MyUserControl"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

由于单元格模板中指定的TextBlockTextBox 将成为可视化树的一部分,因此您可以向上查找所需的任何控件。

【讨论】:

宾果游戏。模板是要走的路。我将使用 XamGrid 的相关示例更新我的问题。你有什么好的文章解释视觉树的东西@Dtex?感谢您为我指明正确的方向。 好吧,我像你一样艰难地学会了:)。实际上我试图绑定一个 DataGridComboBoxColumn ItemsSource。关于DataGrid的具体信息可以参考blogs.msdn.com/b/vinsibal/archive/2008/08/14/… 呵呵。感谢您的链接伙伴。【参考方案2】:

由于这样的事情,作为一般的经验法则,我尽量避免 XAML 的“诡计”,并使 XAML 尽可能简单和简单,并在 ViewModel(或附加属性或IValueConverters 等(如果确实需要)。

如果可能的话,我会给当前 DataContext 的 ViewModel 一个对相关父 ViewModel 的引用(即属性)

public class ThisViewModel : ViewModelBase

    TypeOfAncestorViewModel Parent  get; set; 

改为直接绑定。

&lt;TextBox Text="Binding Parent" /&gt;

【讨论】:

不会还是同样的问题吗?网格绑定到 VM 上的集合,因此子列的范围是集合,而不是 DataContext。在您的示例中, TextBox 看不到父级,因为它的范围是已经由其父网格绑定的集合属性。抱歉,这可能是我的松散描述在这里没有帮助! @Nick 这个答案的意思是:给集合的元素(它们本身应该是视图模型)一个对父视图模型的引用。然而,仔细阅读这个问题,问题不在于它绑定到集合的元素,而是集合本身,这似乎是错误的。

以上是关于WPF 绑定到父 DataContext的主要内容,如果未能解决你的问题,请参考以下文章

wpf usercontrol,将按钮的命令参数绑定到父用户控件

wpf 模板绑定父对象

如何在 WPF 中捕获从子组件到父组件的激活命令?

如何将 WPF 选项卡项标题拉伸到父控件宽度

将 UserControl ListBox ItemSsource 绑定到父 DataContext 时出错

网格大小不绑定到父容器的大小