2012-01-13 38 views
13

Tôi đang cố gắng để ràng buộc tầm nhìn cột đó của một phần tử như thế này:DataGridTextColumn Tầm nhìn Binding

<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> 

nhưng tôi nhận được lỗi này trong VS đầu ra:

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') 

Is có một cách XAML tinh khiết để thực hiện điều này?

Trả lời

35

Các cột của DataGrid là các đối tượng trừu tượng không xuất hiện trong cây hình ảnh hoặc lôgic. Bạn không thể sử dụng ElementNameRelativeSource. Source kết hợp với x:Reference nên làm việc mặc dù:

Visibility="{Binding Source={x:Reference chkColumnVisible}, 
        Path=IsChecked, 
        Converter={StaticResource BooleanToVisibilityConverter}}" 
+0

+1 cho liên kết đến x: Tham chiếu! –

+0

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. –

+0

@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. –

10

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> 
+0

Không hoạt động đối với tôi vì một số lý do ... 'Lỗi đường dẫn BindingExpression: Thuộc tính 'ValidationColumnVisibility' không tìm thấy trên 'đối tượng' '' NameFixupToken '(HashCode = 55620207)'. BindingExpression: Path = ValidationColumnVisibility; DataItem = 'NameFixupToken' (HashCode = 55620207); phần tử đích là 'DataGridTextColumn' (HashCode = 62066456); thuộc tính mục tiêu là 'Hiển thị' (loại 'Hiển thị') ' – Bartosz

Các vấn đề liên quan