DataGridTextColumn 可见性绑定
Posted
技术标签:
【中文标题】DataGridTextColumn 可见性绑定【英文标题】:DataGridTextColumn Visibility Binding 【发布时间】:2012-02-09 11:37:59 【问题描述】:我正在尝试将列可见性绑定到另一个元素的可见性,如下所示:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<CheckBox x:Name="chkColumnVisible" Content="Show column" />
<DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Column1" Visibility="Binding ElementName=chkColumnVisible, Path=IsChecked, Converter=StaticResource BooleanToVisibilityConverter"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
但我在 VS 输出中收到此错误:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsChecked; DataItem=null; target element is 'DataGridTextColumn' (HashCode=48860040); target property is 'Visibility' (type 'Visibility')
有没有一种纯粹的 XAML 方法来实现这一点?
【问题讨论】:
【参考方案1】:DataGrid
的列是未出现在可视化或逻辑树中的抽象对象。您不能使用ElementName
和RelativeSource
。 Source
与 x:Reference
结合应该可以工作:
Visibility="Binding Source=x:Reference chkColumnVisible,
Path=IsChecked,
Converter=StaticResource BooleanToVisibilityConverter"
【讨论】:
谢谢,它有效!但是这样我就可以睡觉了:)...我完全可以理解为什么 RelativeSource 不起作用,因为它是相对于目标的。但是ElementName到底有什么问题?我以为我通过使用 ElementName 为绑定提供了一个绝对源(显然我错了!)所以目标是否在可视树或逻辑树上都没有关系。 @ErenErsonmez:ElementName
使用当前的名称范围来解析名称,据我所知,名称范围依赖于树。
@ErenErsonmez: MSDN: You can refer to elements in code only if they are registered to the appropriate NameScope through RegisterName. For more information, see
WPF XAML Namescopes
-> The names in a XAML namescope can be used to establish relationships between the XAML-defined names of objects and their instance equivalents in an object tree.
谢谢!我知道除了使用代理元素之外,必须有更好的答案。【参考方案2】:
我为它写了一个标记扩展:
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using System.Xaml;
/// <summary>
/// Binds to the datacontext of the current root object or ElementName
/// </summary>
[MarkupExtensionReturnType(typeof(object))]
public class NinjaBinding : MarkupExtension
private static readonly DependencyObject DependencyObject = new DependencyObject();
private static readonly string[] DoNotCopy = "Path", "Source", "ElementName", "RelativeSource", "ValidationRules" ;
private static readonly PropertyInfo[] CopyProperties = typeof(Binding).GetProperties().Where(x => !DoNotCopy.Contains(x.Name)).ToArray();
public NinjaBinding()
public NinjaBinding(Binding binding)
Binding = binding;
public Binding Binding get; set;
private bool IsInDesignMode
get return DesignerProperties.GetIsInDesignMode(DependencyObject);
public override object ProvideValue(IServiceProvider serviceProvider)
if (Binding == null)
throw new ArgumentException("Binding == null");
if (IsInDesignMode)
return DefaultValue(serviceProvider);
Binding binding = null;
if (Binding.ElementName != null)
var reference = new Reference(Binding.ElementName);
var source = reference.ProvideValue(serviceProvider);
if (source == null)
throw new ArgumentException("Could not resolve element");
binding = CreateElementNameBinding(Binding, source);
else if (Binding.RelativeSource !=null)
throw new ArgumentException("RelativeSource not supported");
else
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
if (rootObjectProvider == null)
throw new ArgumentException("rootObjectProvider == null");
binding = CreateDataContextBinding((FrameworkElement) rootObjectProvider.RootObject, Binding);
var provideValue = binding.ProvideValue(serviceProvider);
return provideValue;
private static Binding CreateElementNameBinding(Binding original, object source)
var binding = new Binding()
Path = original.Path,
Source = source,
;
SyncProperties(original, binding);
return binding;
private static Binding CreateDataContextBinding(FrameworkElement rootObject, Binding original)
string path = string.Format("0.1", FrameworkElement.DataContextProperty.Name, original.Path.Path);
var binding = new Binding(path)
Source = rootObject,
;
SyncProperties(original, binding);
return binding;
private static void SyncProperties(Binding source, Binding target)
foreach (var copyProperty in CopyProperties)
var value = copyProperty.GetValue(source);
copyProperty.SetValue(target, value);
foreach (var rule in source.ValidationRules)
target.ValidationRules.Add(rule);
private static object DefaultValue(IServiceProvider serviceProvider)
var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
if (provideValueTarget == null)
throw new ArgumentException("provideValueTarget == null");
var dependencyProperty = (DependencyProperty)provideValueTarget.TargetProperty;
return dependencyProperty.DefaultMetadata.DefaultValue;
它可以绑定到当前根对象 Window, UserControl, ...
的 DataContext示例用法(可见性和可见性是 ViewModel 的属性):
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="DataContext" Visibility="dataGridBox:NinjaBinding Binding=Binding Visibility" />
<DataGridTextColumn Header="Converter" Visibility="dataGridBox:NinjaBinding Binding=Binding Visible, Converter=StaticResource BooleanToVisibilityConverter" />
<DataGridTextColumn Header="ElementName" Visibility="dataGridBox:NinjaBinding Binding=Binding IsChecked, ElementName=CheckBox, Converter=StaticResource BooleanToVisibilityConverter" />
</DataGrid.Columns>
</DataGrid>
【讨论】:
由于某种原因对我不起作用...BindingExpression path error: 'ValidationColumnVisibility' property not found on 'object' ''NameFixupToken' (HashCode=55620207)'. BindingExpression:Path=ValidationColumnVisibility; DataItem='NameFixupToken' (HashCode=55620207); target element is 'DataGridTextColumn' (HashCode=62066456); target property is 'Visibility' (type 'Visibility')
在我的应用程序中完美地使用了 DataTemplateColumn 和 DataGrid。【参考方案3】:
Johan Larsson 的解决方案完美运行,只有来自 Binding 的 FallbackValue 没有被转发,所以我将其更改为:
private object DefaultValue(IServiceProvider serviceProvider)
if (Binding.FallbackValue != null)
return Binding.FallbackValue;
var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
if (provideValueTarget == null)
throw new ArgumentException("provideValueTarget == null");
var dependencyProperty = (DependencyProperty)provideValueTarget.TargetProperty;
return dependencyProperty.DefaultMetadata.DefaultValue;
所以它可以像这样使用,这里以绑定到 Header 为例:
<DataGridTemplateColumn Header="dataGridBox:NinjaBinding Binding=Binding MyHeaderName1, FallbackValue=HeadingNr1" />
【讨论】:
以上是关于DataGridTextColumn 可见性绑定的主要内容,如果未能解决你的问题,请参考以下文章
Silverlight DataGridTextColumn 绑定可见性
在 DataGridTextColumn 中绑定 ViewModel 属性
WPF C# 数据绑定到 DataGridTextColumn