[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.ComponentModel.ISupportInitialize))]
// moved to System.ObjectModel
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.ComponentModel.TypeConverterAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.ComponentModel.TypeDescriptionProviderAttribute))]
namespace System
{
public virtual System.ComponentModel.ICustomTypeDescriptor GetTypeDescriptor(System.Type objectType, object instance) { throw null; }
public virtual bool IsSupportedType(System.Type type) { throw null; }
}
- [System.AttributeUsageAttribute((System.AttributeTargets)(4), Inherited = true)]
- public sealed partial class TypeDescriptionProviderAttribute : System.Attribute
- {
- public TypeDescriptionProviderAttribute(string typeName) { }
- public TypeDescriptionProviderAttribute(System.Type type) { }
- public string TypeName { get { throw null; } }
- }
public sealed partial class TypeDescriptor
{
internal TypeDescriptor() { }
<linker>
<assembly fullname="System.ComponentModel.TypeConverter">
+ <type fullname="MS.Internal.Xml.Linq.ComponentModel.*" />
<type fullname="System.ComponentModel.TypeDescriptor">
<!-- called through reflection by System.ComponentModel.DefaultValueAttribute -->
<method name="ConvertFromInvariantString" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace MS.Internal.Xml.Linq.ComponentModel
+{
+ internal class XTypeDescriptionProvider<T> : TypeDescriptionProvider
+ {
+ public XTypeDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(T)))
+ {
+ }
+
+ public override ICustomTypeDescriptor GetTypeDescriptor(Type type, object instance)
+ {
+ return new XTypeDescriptor<T>(base.GetTypeDescriptor(type, instance));
+ }
+ }
+
+ internal class XTypeDescriptor<T> : CustomTypeDescriptor
+ {
+ public XTypeDescriptor(ICustomTypeDescriptor parent) : base(parent)
+ {
+ }
+
+ public override PropertyDescriptorCollection GetProperties()
+ {
+ return GetProperties(null);
+ }
+
+ public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
+ {
+ PropertyDescriptorCollection properties = new PropertyDescriptorCollection(null);
+ if (attributes == null)
+ {
+ if (typeof(T) == typeof(XElement))
+ {
+ properties.Add(new XElementAttributePropertyDescriptor());
+ properties.Add(new XElementDescendantsPropertyDescriptor());
+ properties.Add(new XElementElementPropertyDescriptor());
+ properties.Add(new XElementElementsPropertyDescriptor());
+ properties.Add(new XElementValuePropertyDescriptor());
+ properties.Add(new XElementXmlPropertyDescriptor());
+ }
+ else if (typeof(T) == typeof(XAttribute))
+ {
+ properties.Add(new XAttributeValuePropertyDescriptor());
+ }
+ }
+ foreach (PropertyDescriptor property in base.GetProperties(attributes))
+ {
+ properties.Add(property);
+ }
+ return properties;
+ }
+ }
+
+ internal abstract class XPropertyDescriptor<T, TProperty> : PropertyDescriptor where T : XObject
+ {
+ public XPropertyDescriptor(string name) : base(name, null)
+ {
+ }
+
+ public override Type ComponentType
+ {
+ get { return typeof(T); }
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public override Type PropertyType
+ {
+ get { return typeof(TProperty); }
+ }
+
+ public override bool SupportsChangeEvents
+ {
+ get { return true; }
+ }
+
+ public override void AddValueChanged(object component, EventHandler handler)
+ {
+ bool hasValueChangedHandler = GetValueChangedHandler(component) != null;
+ base.AddValueChanged(component, handler);
+ if (hasValueChangedHandler)
+ return;
+ T c = component as T;
+ if (c != null && GetValueChangedHandler(component) != null)
+ {
+ c.Changing += new EventHandler<XObjectChangeEventArgs>(OnChanging);
+ c.Changed += new EventHandler<XObjectChangeEventArgs>(OnChanged);
+ }
+ }
+
+ public override bool CanResetValue(object component)
+ {
+ return false;
+ }
+
+ public override void RemoveValueChanged(object component, EventHandler handler)
+ {
+ base.RemoveValueChanged(component, handler);
+ T c = component as T;
+ if (c != null && GetValueChangedHandler(component) == null)
+ {
+ c.Changing -= new EventHandler<XObjectChangeEventArgs>(OnChanging);
+ c.Changed -= new EventHandler<XObjectChangeEventArgs>(OnChanged);
+ }
+ }
+
+ public override void ResetValue(object component)
+ {
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ }
+
+ public override bool ShouldSerializeValue(object component)
+ {
+ return false;
+ }
+
+ protected virtual void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ }
+
+ protected virtual void OnChanging(object sender, XObjectChangeEventArgs args)
+ {
+ }
+ }
+
+ internal class XElementAttributePropertyDescriptor : XPropertyDescriptor<XElement, object>
+ {
+ private XDeferredSingleton<XAttribute> _value;
+ private XAttribute _changeState;
+
+ public XElementAttributePropertyDescriptor() : base("Attribute")
+ {
+ }
+
+ public override object GetValue(object component)
+ {
+ return _value = new XDeferredSingleton<XAttribute>((e, n) => e.Attribute(n), component as XElement, null);
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Add:
+ XAttribute a = sender as XAttribute;
+ if (a != null && _value.element == a.Parent && _value.name == a.Name)
+ {
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Remove:
+ a = sender as XAttribute;
+ if (a != null && _changeState == a)
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ }
+ }
+
+ protected override void OnChanging(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Remove:
+ XAttribute a = sender as XAttribute;
+ _changeState = a != null && _value.element == a.Parent && _value.name == a.Name ? a : null;
+ break;
+ }
+ }
+ }
+
+ internal class XElementDescendantsPropertyDescriptor : XPropertyDescriptor<XElement, IEnumerable<XElement>>
+ {
+ private XDeferredAxis<XElement> _value;
+ private XName _changeState;
+
+ public XElementDescendantsPropertyDescriptor() : base("Descendants")
+ {
+ }
+
+ public override object GetValue(object component)
+ {
+ return _value = new XDeferredAxis<XElement>((e, n) => n != null ? e.Descendants(n) : e.Descendants(), component as XElement, null);
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Add:
+ case XObjectChange.Remove:
+ XElement e = sender as XElement;
+ if (e != null && (_value.name == e.Name || _value.name == null))
+ {
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Name:
+ e = sender as XElement;
+ if (e != null && _value.element != e && _value.name != null && (_value.name == e.Name || _value.name == _changeState))
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ }
+ }
+
+ protected override void OnChanging(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Name:
+ XElement e = sender as XElement;
+ _changeState = e != null ? e.Name : null;
+ break;
+ }
+ }
+ }
+
+ internal class XElementElementPropertyDescriptor : XPropertyDescriptor<XElement, object>
+ {
+ private XDeferredSingleton<XElement> _value;
+ private XElement _changeState;
+
+ public XElementElementPropertyDescriptor() : base("Element")
+ {
+ }
+
+ public override object GetValue(object component)
+ {
+ return _value = new XDeferredSingleton<XElement>((e, n) => e.Element(n), component as XElement, null);
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Add:
+ XElement e = sender as XElement;
+ if (e != null && _value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e)
+ {
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Remove:
+ e = sender as XElement;
+ if (e != null && _changeState == e)
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Name:
+ e = sender as XElement;
+ if (e != null)
+ {
+ if (_value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e)
+ {
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ else if (_changeState == e)
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ }
+ break;
+ }
+ }
+
+ protected override void OnChanging(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Remove:
+ case XObjectChange.Name:
+ XElement e = sender as XElement;
+ _changeState = e != null && _value.element == e.Parent && _value.name == e.Name && _value.element.Element(_value.name) == e ? e : null;
+ break;
+ }
+ }
+ }
+
+ internal class XElementElementsPropertyDescriptor : XPropertyDescriptor<XElement, IEnumerable<XElement>>
+ {
+ private XDeferredAxis<XElement> _value;
+ private object _changeState;
+
+ public XElementElementsPropertyDescriptor() : base("Elements")
+ {
+ }
+
+ public override object GetValue(object component)
+ {
+ return _value = new XDeferredAxis<XElement>((e, n) => n != null ? e.Elements(n) : e.Elements(), component as XElement, null);
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Add:
+ XElement e = sender as XElement;
+ if (e != null && _value.element == e.Parent && (_value.name == e.Name || _value.name == null))
+ {
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Remove:
+ e = sender as XElement;
+ if (e != null && _value.element == (_changeState as XContainer) && (_value.name == e.Name || _value.name == null))
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Name:
+ e = sender as XElement;
+ if (e != null && _value.element == e.Parent && _value.name != null && (_value.name == e.Name || _value.name == (_changeState as XName)))
+ {
+ _changeState = null;
+ OnValueChanged(_value.element, EventArgs.Empty);
+ }
+ break;
+ }
+ }
+
+ protected override void OnChanging(object sender, XObjectChangeEventArgs args)
+ {
+ if (_value == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Remove:
+ XElement e = sender as XElement;
+ _changeState = e != null ? e.Parent : null;
+ break;
+ case XObjectChange.Name:
+ e = sender as XElement;
+ _changeState = e != null ? e.Name : null;
+ break;
+ }
+ }
+ }
+
+ internal class XElementValuePropertyDescriptor : XPropertyDescriptor<XElement, string>
+ {
+ private XElement _element;
+
+ public XElementValuePropertyDescriptor() : base("Value")
+ {
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public override object GetValue(object component)
+ {
+ _element = component as XElement;
+ if (_element == null)
+ return string.Empty;
+ return _element.Value;
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ _element = component as XElement;
+ if (_element == null)
+ return;
+ _element.Value = value as string;
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_element == null)
+ return;
+ switch (args.ObjectChange)
+ {
+ case XObjectChange.Add:
+ case XObjectChange.Remove:
+ if (sender is XElement || sender is XText)
+ {
+ OnValueChanged(_element, EventArgs.Empty);
+ }
+ break;
+ case XObjectChange.Value:
+ if (sender is XText)
+ {
+ OnValueChanged(_element, EventArgs.Empty);
+ }
+ break;
+ }
+ }
+ }
+
+ internal class XElementXmlPropertyDescriptor : XPropertyDescriptor<XElement, string>
+ {
+ private XElement _element;
+
+ public XElementXmlPropertyDescriptor() : base("Xml")
+ {
+ }
+
+ public override object GetValue(object component)
+ {
+ _element = component as XElement;
+ if (_element == null)
+ return string.Empty;
+ return _element.ToString(SaveOptions.DisableFormatting);
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_element == null)
+ return;
+ OnValueChanged(_element, EventArgs.Empty);
+ }
+ }
+
+ internal class XAttributeValuePropertyDescriptor : XPropertyDescriptor<XAttribute, string>
+ {
+ private XAttribute _attribute;
+
+ public XAttributeValuePropertyDescriptor() : base("Value")
+ {
+ }
+
+ public override bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public override object GetValue(object component)
+ {
+ _attribute = component as XAttribute;
+ if (_attribute == null)
+ return string.Empty;
+ return _attribute.Value;
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ _attribute = component as XAttribute;
+ if (_attribute == null)
+ return;
+ _attribute.Value = value as string;
+ }
+
+ protected override void OnChanged(object sender, XObjectChangeEventArgs args)
+ {
+ if (_attribute == null)
+ return;
+ if (args.ObjectChange == XObjectChange.Value)
+ {
+ OnValueChanged(_attribute, EventArgs.Empty);
+ }
+ }
+ }
+
+ internal class XDeferredAxis<T> : IEnumerable<T>, IEnumerable where T : XObject
+ {
+ private Func<XElement, XName, IEnumerable<T>> _func;
+ internal XElement element;
+ internal XName name;
+
+ public XDeferredAxis(Func<XElement, XName, IEnumerable<T>> func, XElement element, XName name)
+ {
+ if (func == null)
+ throw new ArgumentNullException("func");
+ if (element == null)
+ throw new ArgumentNullException("element");
+ _func = func;
+ this.element = element;
+ this.name = name;
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return _func(element, name).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public IEnumerable<T> this[string expandedName]
+ {
+ get
+ {
+ if (expandedName == null)
+ throw new ArgumentNullException("expandedName");
+ if (name == null)
+ {
+ name = expandedName;
+ }
+ else if (name != expandedName)
+ {
+ return Enumerable.Empty<T>();
+ }
+ return this;
+ }
+ }
+ }
+
+ internal class XDeferredSingleton<T> where T : XObject
+ {
+ private Func<XElement, XName, T> _func;
+ internal XElement element;
+ internal XName name;
+
+ public XDeferredSingleton(Func<XElement, XName, T> func, XElement element, XName name)
+ {
+ if (func == null)
+ throw new ArgumentNullException("func");
+ if (element == null)
+ throw new ArgumentNullException("element");
+ _func = func;
+ this.element = element;
+ this.name = name;
+ }
+
+ public T this[string expandedName]
+ {
+ get
+ {
+ if (expandedName == null)
+ throw new ArgumentNullException("expandedName");
+ if (name == null)
+ {
+ name = expandedName;
+ }
+ else if (name != expandedName)
+ {
+ return null;
+ }
+ return _func(element, name);
+ }
+ }
+ }
+}
<Configurations>netcoreapp-Debug;netcoreapp-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="MS\Internal\Xml\Linq\ComponentModel\XComponentModel.cs" />
<Compile Include="System\ComponentModelSwitches.cs" />
<Compile Include="System\ComponentModel\ArrayConverter.cs" />
<Compile Include="System\ComponentModel\BaseNumberConverter.cs" />
<Compile Include="System\ComponentModel\RefreshEventHandler.cs" />
<Compile Include="System\ComponentModel\TypeDescriptor.cs" />
<Compile Include="System\ComponentModel\TypeDescriptionProvider.cs" />
- <Compile Include="System\ComponentModel\TypeDescriptionProviderAttribute.cs" />
<Compile Include="System\ComponentModel\WeakHashtable.cs" />
<Compile Include="System\ComponentModel\Design\IDictionaryService.cs" />
<Compile Include="System\ComponentModel\Design\IExtenderListService.cs" />
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Thread" />
<Reference Include="System.Threading.Timer" />
+ <Reference Include="System.Xml.XDocument" />
</ItemGroup>
</Project>
\ No newline at end of file
<Compile Include="Design\DesignerOptionServiceTests.cs" />
<Compile Include="Design\DesignerTransactionTests.cs" />
<Compile Include="Security\Authentication\ExtendedProtection\ExtendedProtectionPolicyTypeConverterTests.cs" />
+ <Compile Include="XTypeDescriptionProviderTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using Xunit;
+
+namespace System.Xml.Linq.Tests
+{
+ public class XTypeDescriptionProviderTests
+ {
+ [Fact]
+ public void XAttributeValuePropertyDescriptor()
+ {
+ var xatt = new XAttribute("someAttribute", "someValue");
+ var props = TypeDescriptor.GetProperties(xatt);
+
+ var xattrPD = props["Value"];
+ Assert.NotNull(xattrPD);
+ Assert.False(xattrPD.IsReadOnly);
+ Assert.Equal(typeof(XAttribute), xattrPD.ComponentType);
+ Assert.Equal(typeof(string), xattrPD.PropertyType);
+ Assert.True(xattrPD.SupportsChangeEvents);
+ Assert.False(xattrPD.CanResetValue(xatt));
+ Assert.False(xattrPD.ShouldSerializeValue(xatt));
+
+ Assert.Equal(xatt.Value, xattrPD.GetValue(xatt));
+
+ bool valueChanged = false;
+ xattrPD.AddValueChanged(xatt, (o, e) =>
+ {
+ valueChanged = true;
+ });
+ var newValue = "SomeNewValue";
+ xattrPD.SetValue(xatt, newValue);
+
+ Assert.True(valueChanged);
+ Assert.Equal(newValue, xatt.Value);
+ }
+
+ [Fact]
+ public void XElementAttributePropertyDescriptor()
+ {
+ var xel = new XElement("someElement");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelAttPD = props["Attribute"];
+ Assert.NotNull(xelAttPD);
+ Assert.True(xelAttPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelAttPD.ComponentType);
+ Assert.Equal(typeof(object), xelAttPD.PropertyType);
+ Assert.True(xelAttPD.SupportsChangeEvents);
+ Assert.False(xelAttPD.CanResetValue(xel));
+ Assert.False(xelAttPD.ShouldSerializeValue(xel));
+
+ bool valueChanged = false;
+ xelAttPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+
+ var attr1 = new XAttribute("attr1", "value");
+ xel.Add(attr1);
+ Assert.False(valueChanged); // Cannot be triggered until one call to GetValue;
+
+ // value here is a private object, it has a single item indexer that returns an XAttribute from a name.
+ // once you call it once with a name it has the behavior of "binding" the value to that name
+ // so that changes to that name will trigger changed events.
+ // once bound it cannot be rebound to a different name.
+ // only one value (the latest) is tracked by the property descriptor.
+ object value = xelAttPD.GetValue(xel);
+
+ // not exposed, must use reflection to get at it?!
+ var getItemMethod = value.GetType().GetMethod("get_Item", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+ Func<string, XAttribute> getAttribute = (name) => (XAttribute)getItemMethod.Invoke(value, new string[] { name });
+
+ Assert.Equal(attr1, getAttribute(attr1.Name.ToString()));
+
+ attr1.Remove();
+ Assert.True(valueChanged);
+
+ // has been removed
+ Assert.Null(getAttribute(attr1.Name.ToString()));
+
+ valueChanged = false;
+ var attr2 = new XAttribute("attr2", "value2");
+ Assert.Null(getAttribute(attr2.Name.ToString()));
+ Assert.False(valueChanged);
+ xel.Add(attr2);
+ Assert.False(valueChanged); // value is bound to attr1
+ xel.Add(attr1);
+ Assert.True(valueChanged);
+
+ attr2.Remove();
+ attr1.Remove();
+ valueChanged = false;
+
+ // get a new value that hasn't be bound
+ value = xelAttPD.GetValue(xel);
+ // bind it to attr2, which hasn't been added
+ Assert.Null(getAttribute(attr2.Name.ToString()));
+ Assert.False(valueChanged);
+ xel.Add(attr1);
+ Assert.False(valueChanged);
+ xel.Add(attr2);
+ Assert.True(valueChanged);
+ Assert.Equal(attr2, getAttribute(attr2.Name.ToString()));
+ Assert.Null(getAttribute(attr1.Name.ToString()));
+
+ valueChanged = false;
+ attr1.Remove();
+ Assert.False(valueChanged);
+ attr2.Remove();
+ Assert.True(valueChanged);
+ }
+
+ [Fact]
+ public void XElementDescendantsPropertyDescriptor()
+ {
+ var xel = new XElement("someElement");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelDesPD = props["Descendants"];
+ Assert.NotNull(xelDesPD);
+ Assert.True(xelDesPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelDesPD.ComponentType);
+ Assert.Equal(typeof(IEnumerable<XElement>), xelDesPD.PropertyType);
+ Assert.True(xelDesPD.SupportsChangeEvents);
+ Assert.False(xelDesPD.CanResetValue(xel));
+ Assert.False(xelDesPD.ShouldSerializeValue(xel));
+
+ var dess = (IEnumerable<XElement>)xelDesPD.GetValue(xel);
+
+ bool valueChanged = false;
+ xelDesPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+
+ xel.Add(new XElement("c1", new XElement("gc1", new XElement("ggc1"))), new XElement("c2"));
+ Assert.True(valueChanged);
+
+ Assert.Equal(dess, xel.Descendants());
+
+ valueChanged = false;
+ xel.Element("c1").Remove();
+ Assert.True(valueChanged);
+ }
+
+ [Fact]
+ public void XElementElementPropertyDescriptor()
+ {
+ var xel = new XElement("someElement");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelElPD = props["Element"];
+ Assert.True(xelElPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelElPD.ComponentType);
+ Assert.Equal(typeof(object), xelElPD.PropertyType);
+ Assert.True(xelElPD.SupportsChangeEvents);
+ Assert.False(xelElPD.CanResetValue(xel));
+ Assert.False(xelElPD.ShouldSerializeValue(xel));
+
+ bool valueChanged = false;
+ xelElPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+
+ var el1 = new XElement("el1");
+ xel.Add(el1);
+ Assert.False(valueChanged); // Cannot be triggered until one call to GetValue;
+
+ // value here is a private object, it has a single item indexer that returns an XAttribute from a name.
+ // once you call it once with a name it has the behavior of "binding" the value to that name
+ // so that changes to that name will trigger changed events.
+ // once bound it cannot be rebound to a different name.
+ // only one value (the latest) is tracked by the property descriptor.
+ object value = xelElPD.GetValue(xel);
+
+ // not exposed, must use reflection to get at it?!
+ var getItemMethod = value.GetType().GetMethod("get_Item", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+ Func<string, XElement> getElement = (name) => (XElement)getItemMethod.Invoke(value, new string[] { name });
+
+ Assert.Equal(el1, getElement(el1.Name.ToString()));
+
+ el1.Remove();
+ Assert.True(valueChanged);
+
+ // has been removed
+ Assert.Null(getElement(el1.Name.ToString()));
+
+ valueChanged = false;
+ var el2 = new XElement("el2");
+ Assert.Null(getElement(el2.Name.ToString()));
+ Assert.False(valueChanged);
+ xel.Add(el2);
+ Assert.False(valueChanged); // value is bound to attr1
+ xel.Add(el1);
+ Assert.True(valueChanged);
+
+ el2.Remove();
+ el1.Remove();
+ valueChanged = false;
+
+ // get a new value that hasn't be bound
+ value = xelElPD.GetValue(xel);
+ // bind it to attr2, which hasn't been added
+ Assert.Null(getElement(el2.Name.ToString()));
+ Assert.False(valueChanged);
+ xel.Add(el1);
+ Assert.False(valueChanged);
+ xel.Add(el2);
+ Assert.True(valueChanged);
+ Assert.Equal(el2, getElement(el2.Name.ToString()));
+ Assert.Null(getElement(el1.Name.ToString()));
+
+ valueChanged = false;
+ el1.Remove();
+ Assert.False(valueChanged);
+ el2.Remove();
+ Assert.True(valueChanged);
+ }
+
+ [Fact]
+ public void XElementElementsPropertyDescriptor()
+ {
+ var xel = new XElement("someElement");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelElsPD = props["Elements"];
+ Assert.NotNull(xelElsPD);
+ Assert.True(xelElsPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelElsPD.ComponentType);
+ Assert.Equal(typeof(IEnumerable<XElement>), xelElsPD.PropertyType);
+ Assert.True(xelElsPD.SupportsChangeEvents);
+ Assert.False(xelElsPD.CanResetValue(xel));
+ Assert.False(xelElsPD.ShouldSerializeValue(xel));
+
+ var els = (IEnumerable<XElement>)xelElsPD.GetValue(xel);
+
+ bool valueChanged = false;
+ xelElsPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+
+ xel.Add(new XElement("c1"), new XElement("c2"));
+ Assert.True(valueChanged);
+
+ Assert.Equal(els, xel.Elements());
+
+ valueChanged = false;
+ xel.Element("c1").Remove();
+ Assert.True(valueChanged);
+ }
+
+ [Fact]
+ public void XElementValuePropertyDescriptor()
+ {
+ var xel = new XElement("someElement", "someValue");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelValPD = props["Value"];
+ Assert.NotNull(xelValPD);
+ Assert.False(xelValPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelValPD.ComponentType);
+ Assert.Equal(typeof(string), xelValPD.PropertyType);
+ Assert.True(xelValPD.SupportsChangeEvents);
+ Assert.False(xelValPD.CanResetValue(xel));
+ Assert.False(xelValPD.ShouldSerializeValue(xel));
+
+ Assert.Equal(xel.Value, xelValPD.GetValue(xel));
+
+ bool valueChanged = false;
+ xelValPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+ var newValue = "SomeNewValue";
+ xelValPD.SetValue(xel, newValue);
+
+ Assert.True(valueChanged);
+ Assert.Equal(newValue, xel.Value);
+
+ valueChanged = false;
+ xel.Value = "AnotherValue";
+ Assert.True(valueChanged);
+ Assert.Equal(xel.Value, xelValPD.GetValue(xel));
+ }
+
+ [Fact]
+ public void XElementXmlPropertyDescriptor()
+ {
+ var xel = new XElement("someElement");
+ var props = TypeDescriptor.GetProperties(xel);
+
+ var xelXmlPD = props["Xml"];
+ Assert.NotNull(xelXmlPD);
+ Assert.True(xelXmlPD.IsReadOnly);
+ Assert.Equal(typeof(XElement), xelXmlPD.ComponentType);
+ Assert.Equal(typeof(string), xelXmlPD.PropertyType);
+ Assert.True(xelXmlPD.SupportsChangeEvents);
+ Assert.False(xelXmlPD.CanResetValue(xel));
+ Assert.False(xelXmlPD.ShouldSerializeValue(xel));
+
+ Assert.Equal(xel.ToString(), xelXmlPD.GetValue(xel));
+
+ bool valueChanged = false;
+ xelXmlPD.AddValueChanged(xel, (o, e) =>
+ {
+ valueChanged = true;
+ });
+ xel.Value = "abc123";
+ Assert.True(valueChanged);
+ Assert.Equal(xel.ToString(), xelXmlPD.GetValue(xel));
+ }
+ }
+}
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
}
+ [System.AttributeUsageAttribute((System.AttributeTargets)(4), Inherited = true)]
+ public sealed partial class TypeDescriptionProviderAttribute : System.Attribute
+ {
+ public TypeDescriptionProviderAttribute(string typeName) { }
+ public TypeDescriptionProviderAttribute(System.Type type) { }
+ public string TypeName { get { throw null; } }
+ }
}
namespace System.Reflection
{
<Compile Include="System\ComponentModel\PropertyChangingEventArgs.cs" />
<Compile Include="System\ComponentModel\PropertyChangingEventHandler.cs" />
<Compile Include="System\ComponentModel\TypeConverterAttribute.cs" />
+ <Compile Include="System\ComponentModel\TypeDescriptionProviderAttribute.cs" />
<Compile Include="System\Reflection\ICustomTypeProvider.cs" />
<Compile Include="System\Windows\Markup\ValueSerializerAttribute.cs" />
<Compile Include="System\Windows\Input\ICommand.cs" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Linq" />
+ <Reference Include="System.ObjectModel" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
/// An XML attribute is a name/value pair associated with an XML element.
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "Reviewed.")]
+ [System.ComponentModel.TypeDescriptionProvider("MS.Internal.Xml.Linq.ComponentModel.XTypeDescriptionProvider`1[[System.Xml.Linq.XAttribute, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],System.ComponentModel.TypeConverter")]
public class XAttribute : XObject
{
/// <summary>
/// </list>
/// </remarks>
[XmlSchemaProvider(null, IsAny = true)]
+ [System.ComponentModel.TypeDescriptionProvider("MS.Internal.Xml.Linq.ComponentModel.XTypeDescriptionProvider`1[[System.Xml.Linq.XElement, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],System.ComponentModel.TypeConverter")]
public class XElement : XContainer, IXmlSerializable
{
/// <summary>
T:System.ComponentModel.Design.Serialization.RootDesignerSerializerAttribute
T:System.ComponentModel.EditorAttribute
T:System.ComponentModel.ToolboxItemAttribute
+T:System.ComponentModel.TypeDescriptionProviderAttribute
T:System.Configuration.ConfigurationPropertyAttribute
T:System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute
T:System.Diagnostics.CodeAnalysis.SuppressMessageAttribute