2012-02-29 2 views
1

속성은 내 WindowDataContext 등이 하나 개의 세트 같은 XDocument 있습니다 하여 XDocument 바인딩 요소와

Class MainWindow 
    Public Sub New() 
     InitializeComponent() 
     Me.DataContext = <?xml version="1.0" encoding="utf-8"?> 
         <Sketch Format="A4" Author="Aaron" Created="..." Test="Value"> 
          <Item Kind="Line" X1="50" Y1="50" X2="150" Y2="150"> 
           <Item Kind="Rect" X="10" Y="10" Width="30" Height="30"/> 
          </Item> 
          <Item Kind="Line" X1="250" Y1="250" X2="250" Y2="50"> 
           <Item Kind="Ellipse" X="10" Y="10" Width="30" Height="30"/> 
          </Item> 
          <Test Param="Value"/> 
         </Sketch> 
    End Sub 
End Class 

지금 내 프론트 엔드에서 내가 다른 바인딩 경로의 몇 가지를 테스트합니다. 모두 Elements, Element, Attribute으로 작동하지만 Attributes은 저에게 적합하지 않습니다. ElementsIEnumerable<XElement>이고 AttributesIEnumerable<XAttribute>입니다. 정확히 같은 종류의 컬렉션과 모든 것입니다.

<Window Height="320" Title="Main Window" Width="640" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MainWindow"> 
    <UniformGrid Columns="3"> 
     <StackPanel> 
      <Label Foreground="DimGray">Root.Elements.Count</Label> 
      <Label Content="{Binding Path=Root.Elements.Count, FallbackValue=Loading…}"/> 
      <Label Foreground="DimGray">Root.Attributes.Count</Label> 
      <Label Content="{Binding Path=Root.Attributes.Count, FallbackValue=Loading…}"/> 
      <Label Foreground="DimGray">Root.Element[Test]</Label> 
      <Label Content="{Binding Path=Root.Element[Test], FallbackValue=Loading…}"/> 
      <Label Foreground="DimGray">Root.Attribute[Test]</Label> 
      <Label Content="{Binding Path=Root.Attribute[Test], FallbackValue=Loading…}"/> 
     </StackPanel> 
     <StackPanel> 
      <Label Foreground="DimGray">Root.Elements</Label> 
      <ListBox ItemsSource="{Binding Root.Elements}"/> 
      <Label Foreground="DimGray">Root.Attributes</Label> 
      <ListBox ItemsSource="{Binding Root.Attributes}"/> 
     </StackPanel> 
     <StackPanel> 
      <TreeView ItemsSource="{Binding Root.Elements}"> 
       <TreeView.ItemTemplate> 
        <HierarchicalDataTemplate ItemsSource="{Binding Elements}"> 
         <Label Content="{Binding Name}"/> 
        </HierarchicalDataTemplate> 
       </TreeView.ItemTemplate> 
      </TreeView> 
     </StackPanel> 
    </UniformGrid> 
</Window> 

Attributes을 제외하고 모든 것이 올바르게 바인딩되는 이유는 무엇입니까? 어떤 도움을 주셔서 감사합니다. 나는 IS는 (아마도) ElementElementsXContainer에서 상속됩니다, 사실 함께 할 수있는 뭔가를 가지고 있다고 생각하지만,이 설명하지 않는 이유 XElements 자신의 Attribute 작품 ... 사전에

감사합니다! 아론

답변

1

XElement (바인딩에서 직접 사용할 수 없습니다 유일한 방법 Attributes())에 프로퍼티 Attributes 없다, 그래서 의외 바인딩이 작동하지 않습니다 아니에요.

하지만 속성이 없습니다. Elements, 그렇다면 왜 작동합니까? LINQ to XML 객체에는 WPF에서 사용하기위한 특별한 "동적 속성"이 있으므로 (LINQ to XML Dynamic Properties on MSND 참조) XElement에는 동적 속성 Elements이 있지만, Attributes은 없습니다.

아직 이해할 수없는 한 가지가 있습니다. Elements 동적 속성은 elem.Elements[elementName] 형태로만 작동하도록 문서화되어 있습니다. 따라서 코드가 작동한다는 것은 여전히 ​​놀라운 일입니다.

해결 방법에 대해 알고 싶다면 <ObjectDataProvider>을 사용하여 Attributes() 메서드를 호출하는 것을 제외하고는 아무 것도 생각할 필요가 없습니다.

+0

감사합니다. 내 질문에 대한 답변입니다. 다시 한 번 감사드립니다! –

0

스빅은 답변에 정확합니다. XElement에 대한 CustomDescriptor (XElement의 TypeDescriptionProviderAttribute 존재 여부에 따라 결정됨)는 사용자 정의 PropertyDescriptor에 이름 요소 ElementsBuilder를 제공하며 이는 IEnumerable <XElement>을 반환합니다. 인덱서에 의한 바인딩 경로에서이 작업이 수행되면 XContainer.Elements (XName)가 반환되고 그렇지 않으면 XContainer.Elements()가 반환됩니다. 속성이 작동하지 않는 이유는 제공된 동적 속성 설명자가 없다는 것입니다.

아래 코드는 동적 요소 속성과 비슷한 방식으로이 누락 된 기능과 노드 속성을 제공합니다.

//Add this code in App start up  
TypeDescriptor.AddProvider(new XElementAdditionalDynamicPropertiesTypeDescriptionProvider(), 
typeof(XElement)); 

아래 클래스는 기능을 제공하며이 코드는 Elements의 작동 방식과 유사합니다.

public class XDeferredAxis : IEnumerable<XAttribute> 
{ 
    internal XElement element; 
    private Func<XElement, XName, IEnumerable<XAttribute>> func; 
    private XName name; 

    public IEnumerator<XAttribute> GetEnumerator() 
    { 
     return this.func(this.element, this.name).GetEnumerator(); 
    } 

    public XDeferredAxis(Func<XElement, XName, IEnumerable<XAttribute>> func, XElement element, XName name) 
    { 
     if (func == null) 
     { 
      throw new ArgumentNullException("func"); 
     } 
     if (element == null) 
     { 
      throw new ArgumentNullException("element"); 
     } 
     this.func = func; 
     this.element = element; 
     this.name = name; 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 

public class XElementNodesPropertyDescriptor : PropertyDescriptor 
{ 
    private XElement element; 
    private bool childRemoved; 
    public XElementNodesPropertyDescriptor() : base("Nodes", null) 
    { 

    } 
    public override void AddValueChanged(object component, EventHandler handler) 
    { 
     bool flag = base.GetValueChangedHandler(component) != null; 
     base.AddValueChanged(component, handler); 
     if (!flag) 
     { 
      XElement local = component as XElement; 
      if ((local != null) && (base.GetValueChangedHandler(component) != null)) 
      { 
       element = local; 
       local.Changing += new EventHandler<XObjectChangeEventArgs>(this.OnChanging); 
       local.Changed += new EventHandler<XObjectChangeEventArgs>(this.OnChanged); 
      } 
     } 
    } 

    private void OnChanging(object sender, XObjectChangeEventArgs e) 
    { 
     childRemoved = false; 
     if (e.ObjectChange == XObjectChange.Remove) 
     { 
      XObject senderNode = (XObject)sender; 
      if (senderNode.Parent == element) 
      { 
       childRemoved = true; 
      } 
     } 
    } 

    private void OnChanged(object sender, XObjectChangeEventArgs e) 
    { 
     XObject senderNode = (XObject)sender; 
     switch (e.ObjectChange) 
     { 
      case XObjectChange.Add: 
      case XObjectChange.Value: 
      case XObjectChange.Name: 
       if (senderNode.Parent == element) 
       { 
        this.OnValueChanged(element, EventArgs.Empty); 
       } 
       break; 
      case XObjectChange.Remove: 
       if (childRemoved) 
       { 
        this.OnValueChanged(element, EventArgs.Empty); 
       } 
       break; 

     } 
    } 
    public override void RemoveValueChanged(object component, EventHandler handler) 
    { 
     base.RemoveValueChanged(component, handler); 
     XElement local = component as XElement; 
     if ((local != null) && (base.GetValueChangedHandler(component) == null)) 
     { 
      local.Changed -= new EventHandler<XObjectChangeEventArgs>(this.OnChanged); 
     } 
    } 

    public override bool SupportsChangeEvents 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override Type ComponentType 
    { 
     get 
     { 
      return typeof(XElement); 
     } 
    } 

    public override bool IsReadOnly 
    { 
     get 
     { 
      return true; 
     } 
    } 

    public override Type PropertyType 
    { 
     get 
     { 
      return typeof(IEnumerable<XNode>); 
     } 
    } 

    public override bool CanResetValue(object component) 
    { 
     return false; 
    } 

    public override object GetValue(object component) 
    { 
     var nodes= (component as XElement).Nodes(); 
     return nodes; 
    } 

    public override void ResetValue(object component) 
    { 

    } 

    public override void SetValue(object component, object value) 
    { 

    } 

    public override bool ShouldSerializeValue(object component) 
    { 
     return false; 
    } 
} 

public class XElementAttributesPropertyDescriptor : PropertyDescriptor 
{ 
    private XDeferredAxis value; 
    private bool removalIsOwnAttribute; 
    public XElementAttributesPropertyDescriptor() : base("Attributes", null) { 

    } 
    public override void AddValueChanged(object component, EventHandler handler) 
    { 
     bool flag = base.GetValueChangedHandler(component) != null; 
     base.AddValueChanged(component, handler); 
     if (!flag) 
     { 
      XElement local = component as XElement; 
      if ((local != null) && (base.GetValueChangedHandler(component) != null)) 
      { 
       local.Changing += new EventHandler<XObjectChangeEventArgs>(this.OnChanging);    
       local.Changed += new EventHandler<XObjectChangeEventArgs>(this.OnChanged); 
      } 
     } 
    } 

    private void OnChanging(object sender, XObjectChangeEventArgs e) 
    { 
     removalIsOwnAttribute = false; 
     if (e.ObjectChange == XObjectChange.Remove) 
     { 
      var xAttribute = sender as XAttribute; 
      if (xAttribute != null && xAttribute.Parent == value.element) 
      { 
       removalIsOwnAttribute = true; 
      } 
     } 
    } 

    private void OnChanged(object sender, XObjectChangeEventArgs e) 
    { 
     var changeRequired = false; 
     var xAttribute = sender as XAttribute; 

     if (xAttribute != null) 
     { 
      switch (e.ObjectChange) 
      { 
       case XObjectChange.Name: 
       case XObjectChange.Add: 
        if (xAttribute.Parent == value.element) 
        { 
         changeRequired = true; 
        } 
        break; 
       case XObjectChange.Remove: 
        changeRequired = removalIsOwnAttribute; 
        break; 
      } 
      if (changeRequired) 
      { 
       this.OnValueChanged(value.element, EventArgs.Empty); 
      } 
     } 
    } 
    public override void RemoveValueChanged(object component, EventHandler handler) 
    { 
     base.RemoveValueChanged(component, handler); 
     XElement local = component as XElement; 
     if ((local != null) && (base.GetValueChangedHandler(component) == null)) 
     { 
      local.Changed -= new EventHandler<XObjectChangeEventArgs>(this.OnChanged); 
     } 
    } 

    public override bool SupportsChangeEvents 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override Type ComponentType 
    { 
     get 
     { 
      return typeof(XElement); 
     } 
    } 

    public override bool IsReadOnly 
    { 
     get 
     { 
      return true; 
     } 
    } 

    public override Type PropertyType 
    { 
     get 
     { 
      return typeof(IEnumerable<XAttribute>); 
     } 
    } 

    public override bool CanResetValue(object component) 
    { 
     return false; 
    } 

    public override object GetValue(object component) 
    { 
     return (object)(this.value = new XDeferredAxis((Func<XElement, XName, IEnumerable<XAttribute>>)((e, n) => 
     { 
      if (!(n != (XName)null)) 
       return e.Attributes(); 
      return e.Attributes(n); 
     }), component as XElement, (XName)null)); 
    } 

    public override void ResetValue(object component) 
    { 

    } 

    public override void SetValue(object component, object value) 
    { 

    } 

    public override bool ShouldSerializeValue(object component) 
    { 
     return false; 
    } 
} 

public class XElementAdditionalDynamicPropertiesTypeDescriptionProvider: TypeDescriptionProvider 
{ 
    public XElementAdditionalDynamicPropertiesTypeDescriptionProvider() : this(TypeDescriptor.GetProvider(typeof(XElement))) { } 

    protected XElementAdditionalDynamicPropertiesTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) { } 

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
    { 
     var baseTypeDescriptor= base.GetTypeDescriptor(objectType, instance); 
     return new XElementAdditionalDynamicPropertiesTypeDescriptor(baseTypeDescriptor); 
    } 
} 

public class XElementAdditionalDynamicPropertiesTypeDescriptor : CustomTypeDescriptor 
{ 
    public XElementAdditionalDynamicPropertiesTypeDescriptor(ICustomTypeDescriptor original) : base(original) { } 
    public override PropertyDescriptorCollection GetProperties() 
    { 
     return GetProperties(null); 
    } 
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null); 
     if (attributes == null) 
     { 
      descriptors.Add(new XElementAttributesPropertyDescriptor()); 
      descriptors.Add(new XElementNodesPropertyDescriptor()); 
     } 


     foreach (PropertyDescriptor pd in base.GetProperties(attributes)) 
     { 
      descriptors.Add(pd); 
     } 
     return descriptors; 
    } 
}