我尝试将列可见性绑定到另一个元素的可见性,如下所示:
<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方法来实现这一点?
发布于 2012-01-13 16:22:38
DataGrid的列是不出现在可视或逻辑树中的抽象对象。您不能使用ElementName和RelativeSource。不过,结合使用x:Reference和Source应该是可行的:
Visibility="{Binding Source={x:Reference chkColumnVisible},
Path=IsChecked,
Converter={StaticResource BooleanToVisibilityConverter}}"发布于 2014-12-14 08:12:37
我为它写了一个标记扩展:
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;
}
}它允许绑定到当前根对象的窗口{ DataContext,UserControl,...}
示例用法(Visible和Visibility是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>发布于 2018-07-10 02:39:06
Johan Larsson的解决方案工作得很好,只是绑定中的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;
}所以它可以像这样使用,例如绑定到一个头:
<DataGridTemplateColumn Header="{dataGridBox:NinjaBinding Binding={Binding MyHeaderName1, FallbackValue=HeadingNr1}}" />https://stackoverflow.com/questions/8847661
复制相似问题