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>
由于单元格模板中指定的TextBlock
和TextBox
将成为可视化树的一部分,因此您可以向上查找所需的任何控件。
【讨论】:
宾果游戏。模板是要走的路。我将使用 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;
改为直接绑定。
<TextBox Text="Binding Parent" />
【讨论】:
不会还是同样的问题吗?网格绑定到 VM 上的集合,因此子列的范围是集合,而不是 DataContext。在您的示例中, TextBox 看不到父级,因为它的范围是已经由其父网格绑定的集合属性。抱歉,这可能是我的松散描述在这里没有帮助! @Nick 这个答案的意思是:给集合的元素(它们本身应该是视图模型)一个对父视图模型的引用。然而,仔细阅读这个问题,问题不在于它绑定到集合的元素,而是集合本身,这似乎是错误的。以上是关于WPF 绑定到父 DataContext的主要内容,如果未能解决你的问题,请参考以下文章
wpf usercontrol,将按钮的命令参数绑定到父用户控件