Tôi đã viết một markupextension cho nó:
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;
}
}
Nó cho phép liên kết với các DataContext của Objet gốc hiện tại {Window, UserControl, ... }
Sử dụng mẫu (Hiển thị & Khả năng hiển thị là các thuộc tính trong chế độ xem):
<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>
Nguồn
2014-12-14 00:12:36
+1 cho liên kết đến x: Tham chiếu! –
Cảm ơn bạn, nó hoạt động! Nhưng để tôi có thể ngủ:) ... Tôi chắc chắn có thể hiểu tại sao RelativeSource sẽ không hoạt động, vì nó tương đối so với mục tiêu. Nhưng những gì trên trái đất là vấn đề với ElementName ?? Tôi nghĩ rằng tôi đã cho ràng buộc một nguồn tuyệt đối bằng cách sử dụng ElementName (và rõ ràng là tôi sai!) Vì vậy nó sẽ không quan trọng nếu mục tiêu là trên cây hình ảnh hoặc hợp lý hay không. –
@ErenErsonmez: 'ElementName' sử dụng kính hiển vi hiện tại để giải quyết tên và các kính hiển vi phụ thuộc vào các cây theo như tôi biết. –