C# WPF 绑定到父 DataContext
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13415643/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Binding to parent DataContext
提问by Nick
We have a WPF application with a standard MVVM pattern, leveraging Cinch (and therefore MefedMVVM) for View -> ViewModel resolution. This works well, and I can bind the relevant controls to properties on the ViewModel.
我们有一个带有标准 MVVM 模式的 WPF 应用程序,利用 Cinch(以及 MefedMVVM)进行 View -> ViewModel 分辨率。这很有效,我可以将相关控件绑定到 ViewModel 上的属性。
Within a particular View, we have an Infragistics XamGrid. This grid is bound to an ObservableCollection on the ViewModel, and displays the appropriate rows. However, I then have a specific column on this grid which I am trying to bind a TextBox text value to a property on the parent DataContext, rather than the ObservableCollection. This binding is failing.
在特定视图中,我们有一个 Infragistics XamGrid。此网格绑定到 ViewModel 上的 ObservableCollection,并显示适当的行。但是,然后我在此网格上有一个特定的列,我试图将 TextBox 文本值绑定到父 DataContext 上的属性,而不是 ObservableCollection。此绑定失败。
We've gone through several options here including:
我们在这里经历了几个选择,包括:
Using AncestorType to track up the tree and bind to the DataContext of the parent UserControl like so (from the great answerto this question, as well as this one)...
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}Specifying the ElementName and trying to target the top level control directly. Have a look hereif you'd like to read about using ElementName.
Using a 'proxy' FrameorkElement defined in the resources for the UserControl to try and 'pass in' the context as required. We define the element as below, then reference as a static resource...
<FrameworkElement x:Key="ProxyContext" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"></FrameworkElement>
使用AncestorType跟踪了树和绑定到父用户控件的DataContext的,像这样(从伟大的回答这个问题,以及这一个)...
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}指定 ElementName 并尝试直接定位顶级控件。有一个看看这里,如果你想了解使用的ElementName。
使用 UserControl 资源中定义的“代理”FrameorkElement 尝试根据需要“传入”上下文。我们定义元素如下,然后引用为静态资源...
<FrameworkElement x:Key="ProxyContext" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"></FrameworkElement>
In this case the binding finds the FrameworkElement, but can not access anything beyond that (when specifying a Path).
在这种情况下,绑定会找到 FrameworkElement,但不能访问除此之外的任何内容(指定路径时)。
Having read around, it looks quite likely that this is caused by the Infragistics XamGrid building columns outside of the tree. However, even if this is the case, at least options 2 or 3 should work.
仔细阅读后,这很可能是由 Infragistics XamGrid 在树外构建列引起的。但是,即使是这种情况,至少选项 2 或 3 应该可行。
Our last thoughts are that it is related to the V - VM binding, but even using Snoop we've yet to find what the exact issue is. I'm by no means an expert with WPF binding so any pointers would be appreciated.
我们最后的想法是它与 V - VM 绑定有关,但即使使用 Snoop 我们也没有找到确切的问题。我绝不是 WPF 绑定的专家,因此将不胜感激。
EDIT: I have found some templating examples from Infragistics herethat I will try.
编辑:我在这里找到了一些来自 Infragistics 的模板示例,我会尝试。
EDIT 2: As pointed out by @Dtex, templates are the way to go. Here is the relevant snippet for use with a XamGrid:
编辑 2:正如@Dtex 所指出的,模板是要走的路。以下是与 XamGrid 一起使用的相关片段:
<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>
I've left the XML open... you'd simply add the columns you wanted, then close off the relevant tags.
我让 XML 保持打开状态……您只需添加所需的列,然后关闭相关标签。
采纳答案by Dtex
I dont know about XamGridbut that's what i'll do with a standard wpf DataGrid:
我不知道,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>
Since the TextBlockand the TextBoxspecified in the cell templates will be part of the visual tree, you can walk up and find whatever control you need.
由于单元格模板中指定的TextBlock和TextBox将成为可视化树的一部分,您可以向上走并找到您需要的任何控件。
回答by bitbonk
Because of things like this, as a general rule of thumb, I try to avoid as much XAML "trickery" as possible and keep the XAML as dumb and simple as possible and do the rest in the ViewModel (or attached properties or IValueConverters etc. if really necessary).
由于这样的事情,作为一般经验法则,我尽量避免尽可能多的 XAML“诡计”,并尽可能保持 XAML 的愚蠢和简单,并在 ViewModel(或附加属性或 IValueConverters 等)中完成其余工作。如果真的有必要)。
If possible I would give the ViewModel of the current DataContext a reference (i.e. property) to the relevant parent ViewModel
如果可能,我会给当前 DataContext 的 ViewModel 一个对相关父 ViewModel 的引用(即属性)
public class ThisViewModel : ViewModelBase
{
    TypeOfAncestorViewModel Parent { get; set; }
}
and bind against that directly instead.
并直接绑定它。
<TextBox Text="{Binding Parent}" />
<TextBox Text="{Binding Parent}" />

