Browse Source

fixed merge conflict in

src\AddIns\DisplayBindings\WpfDesign\WpfDesign.XamlDom\Project\XamlProperty.cs
Original author: Tobias Gummesson
------------------------------------------------------------------------------------------------------------------------

The previous solution regarding XAML names expected all properties of type string named Name to represent a name in XAML namescope, and this caused trouble with types with a property named Name that did not represent a XAML name. In this case the value of the property tried to be registered as name to the namescope and this caused either the value to be occupied as name, or threw an exception if name already was taken or the value consisted of characters forbidden in XAML names causing the value to not be set at all.

To solve this the value of a Name property is only registered to namescope if the property represents a XAML name (defined by RuntimeNamePropertyAttribute).

Also added a Name property to XamlObject that always sets the name to x:Name attribute, but gets it from either x:Name or the property that represents the XAML name if it exists (both are valid places for name registration).

Fixed a bug in XamlParser where x:Name value was not registered in its namescope.

All other changes (for example changes in PropertyGrid/XamlDesignItem) was to support the Name fixes described above.
pull/53/merge
Siegfried Pammer 13 years ago
parent
commit
76014cd971
  1. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/PropertyGrid/PropertyGrid.cs
  2. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs
  3. 48
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/NameScopeHelper.cs
  4. 181
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj
  5. 111
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs
  6. 11
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
  7. 957
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/PropertyGrid/PropertyGrid.cs

@ -109,7 +109,7 @@ namespace ICSharpCode.WpfDesign.Designer.PropertyGrid @@ -109,7 +109,7 @@ namespace ICSharpCode.WpfDesign.Designer.PropertyGrid
try {
if (string.IsNullOrEmpty(value)) {
OldName = null;
SingleItem.Properties["Name"].Reset();
SingleItem.Name = null;
} else {
OldName = SingleItem.Name;
SingleItem.Name = value;
@ -225,7 +225,7 @@ namespace ICSharpCode.WpfDesign.Designer.PropertyGrid @@ -225,7 +225,7 @@ namespace ICSharpCode.WpfDesign.Designer.PropertyGrid
}
void AddNode(MemberDescriptor md)
{
{
var designProperties = SelectedItems.Select(item => item.Properties.GetProperty(md)).ToArray();
if (!Metadata.IsBrowsable(designProperties[0])) return;

8
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs

@ -49,8 +49,8 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml @@ -49,8 +49,8 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
}
public override string Name {
get { return (string)this.Properties["Name"].ValueOnInstance; }
set { this.Properties["Name"].SetValue(value); }
get { return _xamlObject.Name; }
set { _xamlObject.Name = value; }
}
public override string Key {
@ -70,13 +70,13 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml @@ -70,13 +70,13 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
#if EventHandlerDebugging
Debug.WriteLine("Add event handler to " + this.ComponentType.Name + " (handler count=" + (++totalEventHandlerCount) + ")");
#endif
this.Properties["Name"].ValueChanged += value;
_xamlObject.NameChanged += value;
}
remove {
#if EventHandlerDebugging
Debug.WriteLine("Remove event handler from " + this.ComponentType.Name + " (handler count=" + (--totalEventHandlerCount) + ")");
#endif
this.Properties["Name"].ValueChanged -= value;
_xamlObject.NameChanged -= value;
}
}

48
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/NameScopeHelper.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Static methods to help with <see cref="System.Windows.Markup.INameScope"/> operations on Xaml elements.
/// </summary>
internal static class NameScopeHelper
{
/// <summary>
/// Finds the XAML namescope for the specified object and uses it to unregister the old name and then register the new name.
/// </summary>
/// <param name="namedObject">The object where the name was changed.</param>
/// <param name="oldName">The old name.</param>
/// <param name="newName">The new name.</param>
public static void NameChanged(XamlObject namedObject, string oldName, string newName)
{
var obj = namedObject;
while (obj != null) {
var nameScope = obj.Instance as INameScope;
if (nameScope == null) {
var depObj = obj.Instance as DependencyObject;
if (depObj != null)
nameScope = NameScope.GetNameScope(depObj);
}
if (nameScope != null) {
if (oldName != null) {
try {
nameScope.UnregisterName(oldName);
} catch (Exception x) {
Debug.WriteLine(x.Message);
}
}
if (newName != null) {
nameScope.RegisterName(newName, namedObject.Instance);
}
break;
}
obj = obj.ParentObject;
}
}
}
}

181
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj

@ -1,91 +1,92 @@ @@ -1,91 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{88DA149F-21B2-48AB-82C4-28FB6BDFD783}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.WpfDesign.XamlDom</RootNamespace>
<AssemblyName>ICSharpCode.WpfDesign.XamlDom</AssemblyName>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\..\..\..\Main\ICSharpCode.SharpDevelop.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Globalization#CA1303;-Microsoft.Performance#CA1800</CodeAnalysisRules>
<OutputPath>..\..\..\..\..\..\AddIns\DisplayBindings\WpfDesign\</OutputPath>
<DocumentationFile>..\..\..\..\..\..\AddIns\DisplayBindings\WpfDesign\ICSharpCode.WpfDesign.XamlDom.xml</DocumentationFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SourceAnalysisOverrideSettingsFile>C:\Users\Daniel\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="PresentationCore">
<Private>False</Private>
</Reference>
<Reference Include="PresentationFramework">
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Xaml" />
<Reference Include="WindowsBase">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="CollectionElementsCollection.cs" />
<Compile Include="CollectionSupport.cs" />
<Compile Include="IXamlErrorSink.cs" />
<Compile Include="MarkupExtensionParser.cs" />
<Compile Include="MarkupExtensionPrinter.cs" />
<Compile Include="PositionXmlDocument.cs" />
<Compile Include="XamlConstants.cs" />
<Compile Include="XamlDocument.cs" />
<Compile Include="XamlLoadException.cs" />
<Compile Include="XamlObject.cs" />
<Compile Include="XamlObjectServiceProvider.cs" />
<Compile Include="XamlParser.cs" />
<Compile Include="XamlParserSettings.cs" />
<Compile Include="XamlProperty.cs" />
<Compile Include="XamlPropertyInfo.cs" />
<Compile Include="XamlPropertyValue.cs" />
<Compile Include="XamlStaticTools.cs" />
<Compile Include="XamlTextValue.cs" />
<Compile Include="XamlTypeFinder.cs" />
<Compile Include="XamlTypeResolverProvider.cs" />
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{88DA149F-21B2-48AB-82C4-28FB6BDFD783}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.WpfDesign.XamlDom</RootNamespace>
<AssemblyName>ICSharpCode.WpfDesign.XamlDom</AssemblyName>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\..\..\..\Main\ICSharpCode.SharpDevelop.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Globalization#CA1303;-Microsoft.Performance#CA1800</CodeAnalysisRules>
<OutputPath>..\..\..\..\..\..\AddIns\DisplayBindings\WpfDesign\</OutputPath>
<DocumentationFile>..\..\..\..\..\..\AddIns\DisplayBindings\WpfDesign\ICSharpCode.WpfDesign.XamlDom.xml</DocumentationFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SourceAnalysisOverrideSettingsFile>C:\Users\Daniel\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="PresentationCore">
<Private>False</Private>
</Reference>
<Reference Include="PresentationFramework">
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Xaml" />
<Reference Include="WindowsBase">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="CollectionElementsCollection.cs" />
<Compile Include="CollectionSupport.cs" />
<Compile Include="IXamlErrorSink.cs" />
<Compile Include="MarkupExtensionParser.cs" />
<Compile Include="MarkupExtensionPrinter.cs" />
<Compile Include="NameScopeHelper.cs" />
<Compile Include="PositionXmlDocument.cs" />
<Compile Include="XamlConstants.cs" />
<Compile Include="XamlDocument.cs" />
<Compile Include="XamlLoadException.cs" />
<Compile Include="XamlObject.cs" />
<Compile Include="XamlObjectServiceProvider.cs" />
<Compile Include="XamlParser.cs" />
<Compile Include="XamlParserSettings.cs" />
<Compile Include="XamlProperty.cs" />
<Compile Include="XamlPropertyInfo.cs" />
<Compile Include="XamlPropertyValue.cs" />
<Compile Include="XamlStaticTools.cs" />
<Compile Include="XamlTextValue.cs" />
<Compile Include="XamlTypeFinder.cs" />
<Compile Include="XamlTypeResolverProvider.cs" />
</ItemGroup>
</Project>

111
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlObject.cs

@ -24,7 +24,10 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -24,7 +24,10 @@ namespace ICSharpCode.WpfDesign.XamlDom
Type elementType;
object instance;
List<XamlProperty> properties = new List<XamlProperty>();
string contentPropertyName;
XamlProperty nameProperty;
string runtimeNameProperty;
/// <summary>For use by XamlParser only.</summary>
internal XamlObject(XamlDocument document, XmlElement element, Type elementType, object instance)
{
@ -37,6 +40,11 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -37,6 +40,11 @@ namespace ICSharpCode.WpfDesign.XamlDom
ServiceProvider = new XamlObjectServiceProvider(this);
CreateWrapper();
var rnpAttrs = elementType.GetCustomAttributes(typeof(RuntimeNamePropertyAttribute), true) as RuntimeNamePropertyAttribute[];
if (rnpAttrs != null && rnpAttrs.Length > 0 && !String.IsNullOrEmpty(rnpAttrs[0].Name)) {
runtimeNameProperty = rnpAttrs[0].Name;
}
}
/// <summary>For use by XamlParser only.</summary>
@ -193,6 +201,11 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -193,6 +201,11 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
UpdateMarkupExtensionChain();
if (property == NameProperty) {
if (NameChanged != null)
NameChanged(this, EventArgs.Empty);
}
}
void UpdateMarkupExtensionChain()
@ -273,8 +286,6 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -273,8 +286,6 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
string contentPropertyName;
/// <summary>
/// Gets the name of the content property.
/// </summary>
@ -284,6 +295,54 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -284,6 +295,54 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
/// <summary>
/// Gets which property name of the type maps to the XAML x:Name attribute.
/// </summary>
public string RuntimeNameProperty {
get {
return runtimeNameProperty;
}
}
/// <summary>
/// Gets which property of the type maps to the XAML x:Name attribute.
/// </summary>
public XamlProperty NameProperty {
get {
if(nameProperty == null && runtimeNameProperty != null)
nameProperty = FindOrCreateProperty(runtimeNameProperty);
return nameProperty;
}
}
/// <summary>
/// Gets/Sets the name of this XamlObject.
/// </summary>
public string Name {
get
{
string name = GetXamlAttribute("Name");
if (String.IsNullOrEmpty(name)) {
if (NameProperty != null && NameProperty.IsSet)
name = (string)NameProperty.ValueOnInstance;
}
if (name == String.Empty)
name = null;
return name;
}
set
{
if (String.IsNullOrEmpty(value))
this.SetXamlAttribute("Name", null);
else
this.SetXamlAttribute("Name", value);
}
}
/// <summary>
/// Finds the specified property, or creates it if it doesn't exist.
/// </summary>
@ -353,10 +412,51 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -353,10 +412,51 @@ namespace ICSharpCode.WpfDesign.XamlDom
/// </summary>
public void SetXamlAttribute(string name, string value)
{
XamlProperty runtimeNameProperty = null;
bool isNameChange = false;
if (name == "Name") {
isNameChange = true;
string oldName = GetXamlAttribute("Name");
if (String.IsNullOrEmpty(oldName)) {
runtimeNameProperty = this.NameProperty;
if (runtimeNameProperty != null) {
if (runtimeNameProperty.IsSet)
oldName = (string)runtimeNameProperty.ValueOnInstance;
else
runtimeNameProperty = null;
}
}
if (String.IsNullOrEmpty(oldName))
oldName = null;
NameScopeHelper.NameChanged(this, oldName, value);
}
if (value == null)
element.RemoveAttribute(name, XamlConstants.XamlNamespace);
else
element.SetAttribute(name, XamlConstants.XamlNamespace, value);
if (isNameChange) {
bool nameChangedAlreadyRaised = false;
if (runtimeNameProperty != null) {
var handler = new EventHandler((sender, e) => nameChangedAlreadyRaised = true);
this.NameChanged += handler;
try {
runtimeNameProperty.Reset();
}
finally {
this.NameChanged -= handler;
}
}
if (NameChanged != null && !nameChangedAlreadyRaised)
NameChanged(this, EventArgs.Empty);
}
}
/// <summary>
@ -399,6 +499,11 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -399,6 +499,11 @@ namespace ICSharpCode.WpfDesign.XamlDom
return markupExtensionName;
}
/// <summary>
/// Is raised when the name of this XamlObject changes.
/// </summary>
public event EventHandler NameChanged;
}
abstract class MarkupExtensionWrapper

11
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs

@ -244,8 +244,17 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -244,8 +244,17 @@ namespace ICSharpCode.WpfDesign.XamlDom
if (attribute.Name == "xml:space") {
continue;
}
if (GetAttributeNamespace(attribute) == XamlConstants.XamlNamespace)
if (GetAttributeNamespace(attribute) == XamlConstants.XamlNamespace) {
if (attribute.LocalName == "Name") {
try {
NameScopeHelper.NameChanged(obj, null, attribute.Value);
} catch (Exception x) {
ReportException(x, attribute);
}
}
continue;
}
ParseObjectAttribute(obj, attribute);
}

957
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs

@ -1,351 +1,351 @@ @@ -1,351 +1,351 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Describes a property on a <see cref="XamlObject"/>.
/// </summary>
[DebuggerDisplay("XamlProperty: {PropertyName}")]
public sealed class XamlProperty
{
XamlObject parentObject;
internal readonly XamlPropertyInfo propertyInfo;
XamlPropertyValue propertyValue;
CollectionElementsCollection collectionElements;
bool isCollection;
bool isResources;
static readonly IList<XamlPropertyValue> emptyCollectionElementsArray = new XamlPropertyValue[0];
// for use by parser only
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo, XamlPropertyValue propertyValue)
: this(parentObject, propertyInfo)
{
PossiblyNameChanged(null, propertyValue);
this.propertyValue = propertyValue;
if (propertyValue != null) {
propertyValue.ParentProperty = this;
}
UpdateValueOnInstance();
}
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo)
{
this.parentObject = parentObject;
this.propertyInfo = propertyInfo;
if (propertyInfo.IsCollection) {
isCollection = true;
collectionElements = new CollectionElementsCollection(this);
if (propertyInfo.Name.Equals(XamlConstants.ResourcesPropertyName, StringComparison.Ordinal) &&
propertyInfo.ReturnType == typeof(ResourceDictionary)) {
isResources = true;
}
}
}
/// <summary>
/// Gets the parent object for which this property was declared.
/// </summary>
public XamlObject ParentObject {
get { return parentObject; }
}
/// <summary>
/// Gets the property name.
/// </summary>
public string PropertyName {
get { return propertyInfo.Name; }
}
/// <summary>
/// Gets the type the property is declared on.
/// </summary>
public Type PropertyTargetType {
get { return propertyInfo.TargetType; }
}
/// <summary>
/// Gets if this property is an attached property.
/// </summary>
public bool IsAttached {
get { return propertyInfo.IsAttached; }
}
/// <summary>
/// Gets if this property is an event.
/// </summary>
public bool IsEvent {
get { return propertyInfo.IsEvent; }
}
/// <summary>
/// Gets the return type of the property.
/// </summary>
public Type ReturnType {
get { return propertyInfo.ReturnType; }
}
/// <summary>
/// Gets the type converter used to convert property values to/from string.
/// </summary>
public TypeConverter TypeConverter {
get { return propertyInfo.TypeConverter; }
}
/// <summary>
/// Gets the category of the property.
/// </summary>
public string Category {
get { return propertyInfo.Category; }
}
/// <summary>
/// Gets the value of the property. Can be null if the property is a collection property.
/// </summary>
public XamlPropertyValue PropertyValue {
get { return propertyValue; }
set { SetPropertyValue(value); }
}
/// <summary>
/// Gets if the property represents the FrameworkElement.Resources property that holds a locally-defined resource dictionary.
/// </summary>
public bool IsResources {
get { return isResources; }
}
/// <summary>
/// Gets if the property is a collection property.
/// </summary>
public bool IsCollection {
get { return isCollection; }
}
/// <summary>
/// Gets the collection elements of the property. Is empty if the property is not a collection.
/// </summary>
public IList<XamlPropertyValue> CollectionElements {
get { return collectionElements ?? emptyCollectionElementsArray; }
}
/// <summary>
/// Gets if the property is set.
/// </summary>
public bool IsSet {
get { return propertyValue != null ||
_propertyElement != null; // collection
}
}
/// <summary>
/// Occurs when the value of the IsSet property has changed.
/// </summary>
public event EventHandler IsSetChanged;
/// <summary>
/// Occurs when the value of the property has changed.
/// </summary>
public event EventHandler ValueChanged;
/// <summary>
/// Occurs when MarkupExtension evaluated PropertyValue dosn't changed but ValueOnInstance does.
/// </summary>
public event EventHandler ValueOnInstanceChanged;
void SetPropertyValue(XamlPropertyValue value)
{
// Binding...
//if (IsCollection) {
// throw new InvalidOperationException("Cannot set the value of collection properties.");
//}
bool wasSet = this.IsSet;
PossiblyNameChanged(propertyValue, value);
//reset expression
var xamlObject = propertyValue as XamlObject;
if (xamlObject != null && xamlObject.IsMarkupExtension)
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
propertyValue = value;
propertyValue.ParentProperty = this;
propertyValue.AddNodeTo(this);
UpdateValueOnInstance();
ParentObject.OnPropertyChanged(this);
if (!wasSet) {
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
internal void UpdateValueOnInstance()
{
if (PropertyValue != null) {
try {
ValueOnInstance = PropertyValue.GetValueFor(propertyInfo);
}
catch {
Debug.WriteLine("UpdateValueOnInstance() failed");
}
}
}
/// <summary>
/// Resets the properties value.
/// </summary>
public void Reset()
{
if (IsSet) {
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
ParentObject.OnPropertyChanged(this);
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
}
void ResetInternal()
{
if (propertyValue != null) {
propertyValue.RemoveNodeFromParent();
propertyValue.ParentProperty = null;
propertyValue = null;
}
if (_propertyElement != null) {
_propertyElement.ParentNode.RemoveChild(_propertyElement);
_propertyElement = null;
}
}
XmlElement _propertyElement;
internal void ParserSetPropertyElement(XmlElement propertyElement)
{
XmlElement oldPropertyElement = _propertyElement;
if (oldPropertyElement == propertyElement) return;
_propertyElement = propertyElement;
if (oldPropertyElement != null && IsCollection) {
Debug.WriteLine("Property element for " + this.PropertyName + " already exists, merging..");
foreach (XamlPropertyValue val in this.collectionElements) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
oldPropertyElement.ParentNode.RemoveChild(oldPropertyElement);
}
}
bool IsFirstChildResources(XamlObject obj)
{
return obj.XmlElement.FirstChild != null &&
obj.XmlElement.FirstChild.Name.EndsWith("." + XamlConstants.ResourcesPropertyName) &&
obj.Properties.Where((prop) => prop.IsResources).FirstOrDefault() != null;
}
XmlElement CreatePropertyElement()
{
string ns = parentObject.OwnerDocument.GetNamespaceFor(parentObject.ElementType);
return parentObject.OwnerDocument.XmlDocument.CreateElement(
parentObject.OwnerDocument.GetPrefixForNamespace(ns),
parentObject.ElementType.Name + "." + this.PropertyName,
ns
);
}
internal void AddChildNodeToProperty(XmlNode newChildNode)
{
if (this.IsCollection) {
// this is the default collection
InsertNodeInCollection(newChildNode, collectionElements.Count);
return;
}
if (_propertyElement == null) {
if (PropertyName == parentObject.ContentPropertyName) {
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(newChildNode, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(newChildNode, parentObject.XmlElement.FirstChild);
return;
}
_propertyElement = CreatePropertyElement();
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(_propertyElement, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(_propertyElement, parentObject.XmlElement.FirstChild);
}
_propertyElement.AppendChild(newChildNode);
}
internal void InsertNodeInCollection(XmlNode newChildNode, int index)
{
Debug.Assert(index >= 0 && index <= collectionElements.Count);
XmlElement collection = _propertyElement;
if (collection == null) {
if (collectionElements.Count == 0 && this.PropertyName != this.ParentObject.ContentPropertyName) {
// we have to create the collection element
_propertyElement = CreatePropertyElement();
if (this.IsResources) {
parentObject.XmlElement.PrependChild(_propertyElement);
} else {
parentObject.XmlElement.AppendChild(_propertyElement);
}
collection = _propertyElement;
} else {
// this is the default collection
collection = parentObject.XmlElement;
}
}
if (collectionElements.Count == 0) {
// collection is empty -> we may insert anywhere
collection.AppendChild(newChildNode);
} else if (index == collectionElements.Count) {
// insert after last element in collection
collection.InsertAfter(newChildNode, collectionElements[collectionElements.Count - 1].GetNodeForCollection());
} else {
// insert before specified index
collection.InsertBefore(newChildNode, collectionElements[index].GetNodeForCollection());
}
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Describes a property on a <see cref="XamlObject"/>.
/// </summary>
[DebuggerDisplay("XamlProperty: {PropertyName}")]
public sealed class XamlProperty
{
XamlObject parentObject;
internal readonly XamlPropertyInfo propertyInfo;
XamlPropertyValue propertyValue;
CollectionElementsCollection collectionElements;
bool isCollection;
bool isResources;
static readonly IList<XamlPropertyValue> emptyCollectionElementsArray = new XamlPropertyValue[0];
// for use by parser only
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo, XamlPropertyValue propertyValue)
: this(parentObject, propertyInfo)
{
PossiblyNameChanged(null, propertyValue);
this.propertyValue = propertyValue;
if (propertyValue != null) {
propertyValue.ParentProperty = this;
}
UpdateValueOnInstance();
}
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo)
{
this.parentObject = parentObject;
this.propertyInfo = propertyInfo;
if (propertyInfo.IsCollection) {
isCollection = true;
collectionElements = new CollectionElementsCollection(this);
if (propertyInfo.Name.Equals(XamlConstants.ResourcesPropertyName, StringComparison.Ordinal) &&
propertyInfo.ReturnType == typeof(ResourceDictionary)) {
isResources = true;
}
}
}
/// <summary>
/// Gets the parent object for which this property was declared.
/// </summary>
public XamlObject ParentObject {
get { return parentObject; }
}
/// <summary>
/// Gets the property name.
/// </summary>
public string PropertyName {
get { return propertyInfo.Name; }
}
/// <summary>
/// Gets the type the property is declared on.
/// </summary>
public Type PropertyTargetType {
get { return propertyInfo.TargetType; }
}
/// <summary>
/// Gets if this property is an attached property.
/// </summary>
public bool IsAttached {
get { return propertyInfo.IsAttached; }
}
/// <summary>
/// Gets if this property is an event.
/// </summary>
public bool IsEvent {
get { return propertyInfo.IsEvent; }
}
/// <summary>
/// Gets the return type of the property.
/// </summary>
public Type ReturnType {
get { return propertyInfo.ReturnType; }
}
/// <summary>
/// Gets the type converter used to convert property values to/from string.
/// </summary>
public TypeConverter TypeConverter {
get { return propertyInfo.TypeConverter; }
}
/// <summary>
/// Gets the category of the property.
/// </summary>
public string Category {
get { return propertyInfo.Category; }
}
/// <summary>
/// Gets the value of the property. Can be null if the property is a collection property.
/// </summary>
public XamlPropertyValue PropertyValue {
get { return propertyValue; }
set { SetPropertyValue(value); }
}
/// <summary>
/// Gets if the property represents the FrameworkElement.Resources property that holds a locally-defined resource dictionary.
/// </summary>
public bool IsResources {
get { return isResources; }
}
/// <summary>
/// Gets if the property is a collection property.
/// </summary>
public bool IsCollection {
get { return isCollection; }
}
/// <summary>
/// Gets the collection elements of the property. Is empty if the property is not a collection.
/// </summary>
public IList<XamlPropertyValue> CollectionElements {
get { return collectionElements ?? emptyCollectionElementsArray; }
}
/// <summary>
/// Gets if the property is set.
/// </summary>
public bool IsSet {
get { return propertyValue != null ||
_propertyElement != null; // collection
}
}
/// <summary>
/// Occurs when the value of the IsSet property has changed.
/// </summary>
public event EventHandler IsSetChanged;
/// <summary>
/// Occurs when the value of the property has changed.
/// </summary>
public event EventHandler ValueChanged;
/// <summary>
/// Occurs when MarkupExtension evaluated PropertyValue dosn't changed but ValueOnInstance does.
/// </summary>
public event EventHandler ValueOnInstanceChanged;
void SetPropertyValue(XamlPropertyValue value)
{
// Binding...
//if (IsCollection) {
// throw new InvalidOperationException("Cannot set the value of collection properties.");
//}
bool wasSet = this.IsSet;
PossiblyNameChanged(propertyValue, value);
//reset expression
var xamlObject = propertyValue as XamlObject;
if (xamlObject != null && xamlObject.IsMarkupExtension)
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
propertyValue = value;
propertyValue.ParentProperty = this;
propertyValue.AddNodeTo(this);
UpdateValueOnInstance();
ParentObject.OnPropertyChanged(this);
if (!wasSet) {
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
internal void UpdateValueOnInstance()
{
if (PropertyValue != null) {
try {
ValueOnInstance = PropertyValue.GetValueFor(propertyInfo);
}
catch {
Debug.WriteLine("UpdateValueOnInstance() failed");
}
}
}
/// <summary>
/// Resets the properties value.
/// </summary>
public void Reset()
{
if (IsSet) {
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
ParentObject.OnPropertyChanged(this);
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
}
void ResetInternal()
{
if (propertyValue != null) {
propertyValue.RemoveNodeFromParent();
propertyValue.ParentProperty = null;
propertyValue = null;
}
if (_propertyElement != null) {
_propertyElement.ParentNode.RemoveChild(_propertyElement);
_propertyElement = null;
}
}
XmlElement _propertyElement;
internal void ParserSetPropertyElement(XmlElement propertyElement)
{
XmlElement oldPropertyElement = _propertyElement;
if (oldPropertyElement == propertyElement) return;
_propertyElement = propertyElement;
if (oldPropertyElement != null && IsCollection) {
Debug.WriteLine("Property element for " + this.PropertyName + " already exists, merging..");
foreach (XamlPropertyValue val in this.collectionElements) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
oldPropertyElement.ParentNode.RemoveChild(oldPropertyElement);
}
}
bool IsFirstChildResources(XamlObject obj)
{
return obj.XmlElement.FirstChild != null &&
obj.XmlElement.FirstChild.Name.EndsWith("." + XamlConstants.ResourcesPropertyName) &&
obj.Properties.Where((prop) => prop.IsResources).FirstOrDefault() != null;
}
XmlElement CreatePropertyElement()
{
string ns = parentObject.OwnerDocument.GetNamespaceFor(parentObject.ElementType);
return parentObject.OwnerDocument.XmlDocument.CreateElement(
parentObject.OwnerDocument.GetPrefixForNamespace(ns),
parentObject.ElementType.Name + "." + this.PropertyName,
ns
);
}
internal void AddChildNodeToProperty(XmlNode newChildNode)
{
if (this.IsCollection) {
// this is the default collection
InsertNodeInCollection(newChildNode, collectionElements.Count);
return;
}
if (_propertyElement == null) {
if (PropertyName == parentObject.ContentPropertyName) {
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(newChildNode, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(newChildNode, parentObject.XmlElement.FirstChild);
return;
}
_propertyElement = CreatePropertyElement();
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(_propertyElement, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(_propertyElement, parentObject.XmlElement.FirstChild);
}
_propertyElement.AppendChild(newChildNode);
}
internal void InsertNodeInCollection(XmlNode newChildNode, int index)
{
Debug.Assert(index >= 0 && index <= collectionElements.Count);
XmlElement collection = _propertyElement;
if (collection == null) {
if (collectionElements.Count == 0 && this.PropertyName != this.ParentObject.ContentPropertyName) {
// we have to create the collection element
_propertyElement = CreatePropertyElement();
if (this.IsResources) {
parentObject.XmlElement.PrependChild(_propertyElement);
} else {
parentObject.XmlElement.AppendChild(_propertyElement);
}
collection = _propertyElement;
} else {
// this is the default collection
collection = parentObject.XmlElement;
}
}
if (collectionElements.Count == 0) {
// collection is empty -> we may insert anywhere
collection.AppendChild(newChildNode);
} else if (index == collectionElements.Count) {
// insert after last element in collection
collection.InsertAfter(newChildNode, collectionElements[collectionElements.Count - 1].GetNodeForCollection());
} else {
// insert before specified index
collection.InsertBefore(newChildNode, collectionElements[index].GetNodeForCollection());
}
}
internal XmlAttribute SetAttribute(string value)
@ -353,158 +353,135 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -353,158 +353,135 @@ namespace ICSharpCode.WpfDesign.XamlDom
string name;
var element = ParentObject.XmlElement;
if (IsAttached)
{
if (IsAttached) {
name = PropertyTargetType.Name + "." + PropertyName;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
string prefix = element.GetPrefixOfNamespace(ns);
string prefix = element.GetPrefixOfNamespace(ns);
if (String.IsNullOrEmpty(prefix))
{
prefix = ParentObject.OwnerDocument.GetPrefixForNamespace(ns);
}
if (String.IsNullOrEmpty(prefix)) {
prefix = ParentObject.OwnerDocument.GetPrefixForNamespace(ns);
}
if (!string.IsNullOrEmpty(prefix))
{
if (!string.IsNullOrEmpty(prefix)) {
element.SetAttribute(name, ns, value);
return element.GetAttributeNode(name, ns);
}
}
else
{
} else {
name = PropertyName;
}
element.SetAttribute(name, value);
return element.GetAttributeNode(name);
}
internal string GetNameForMarkupExtension()
{
if (IsAttached) {
string name = PropertyTargetType.Name + "." + PropertyName;
var element = ParentObject.XmlElement;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
var prefix = element.GetPrefixOfNamespace(ns);
if (string.IsNullOrEmpty(prefix))
return name;
else
return prefix + ":" + name;
}
else
return PropertyName;
}
/// <summary>
/// used internally by the XamlParser.
/// Add a collection element that already is part of the XML DOM.
/// </summary>
internal void ParserAddCollectionElement(XmlElement collectionPropertyElement, XamlPropertyValue val)
{
if (collectionPropertyElement != null && _propertyElement == null) {
ParserSetPropertyElement(collectionPropertyElement);
}
collectionElements.AddInternal(val);
val.ParentProperty = this;
if (collectionPropertyElement != _propertyElement) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
}
/// <summary>
/// Gets/Sets the value of the property on the instance without updating the XAML document.
/// </summary>
public object ValueOnInstance {
get {
if (IsEvent) {
if (propertyValue != null)
return propertyValue.GetValueFor(null);
else
return null;
} else {
return propertyInfo.GetValue(parentObject.Instance);
}
}
set {
propertyInfo.SetValue(parentObject.Instance, value);
if (ValueOnInstanceChanged != null)
ValueOnInstanceChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Gets if this property is considered "advanced" and should be hidden by default in a property grid.
/// </summary>
public bool IsAdvanced {
get { return propertyInfo.IsAdvanced; }
}
/// <summary>
/// Gets the dependency property.
/// </summary>
public DependencyProperty DependencyProperty {
get {
return propertyInfo.DependencyProperty;
}
}
void PossiblyNameChanged(XamlPropertyValue oldValue, XamlPropertyValue newValue)
{
if (PropertyName == "Name" && ReturnType == typeof(string)) {
string oldName = null;
string newName = null;
var oldTextValue = oldValue as XamlTextValue;
if (oldTextValue != null) oldName = oldTextValue.Text;
var newTextValue = newValue as XamlTextValue;
if (newTextValue != null) newName = newTextValue.Text;
var obj = ParentObject;
while (obj != null) {
var nameScope = obj.Instance as INameScope;
if (nameScope == null) {
if (obj.Instance is DependencyObject)
nameScope = NameScope.GetNameScope((DependencyObject)obj.Instance);
}
if (nameScope != null) {
if (oldName != null) {
try {
nameScope.UnregisterName(oldName);
} catch (Exception x) {
Debug.WriteLine(x.Message);
}
}
if (newName != null) {
nameScope.RegisterName(newName, ParentObject.Instance);
}
break;
}
obj = obj.ParentObject;
}
}
}
/*public bool IsAttributeSyntax {
get {
return attribute != null;
}
}
public bool IsElementSyntax {
get {
return element != null;
}
}
public bool IsImplicitDefaultProperty {
get {
return attribute == null && element == null;
}
}*/
}
}
}
internal string GetNameForMarkupExtension()
{
if (IsAttached) {
string name = PropertyTargetType.Name + "." + PropertyName;
var element = ParentObject.XmlElement;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
var prefix = element.GetPrefixOfNamespace(ns);
if (string.IsNullOrEmpty(prefix))
return name;
else
return prefix + ":" + name;
} else
return PropertyName;
}
/// <summary>
/// used internally by the XamlParser.
/// Add a collection element that already is part of the XML DOM.
/// </summary>
internal void ParserAddCollectionElement(XmlElement collectionPropertyElement, XamlPropertyValue val)
{
if (collectionPropertyElement != null && _propertyElement == null) {
ParserSetPropertyElement(collectionPropertyElement);
}
collectionElements.AddInternal(val);
val.ParentProperty = this;
if (collectionPropertyElement != _propertyElement) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
}
/// <summary>
/// Gets/Sets the value of the property on the instance without updating the XAML document.
/// </summary>
public object ValueOnInstance {
get {
if (IsEvent) {
if (propertyValue != null)
return propertyValue.GetValueFor(null);
else
return null;
} else {
return propertyInfo.GetValue(parentObject.Instance);
}
}
set {
propertyInfo.SetValue(parentObject.Instance, value);
if (ValueOnInstanceChanged != null)
ValueOnInstanceChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Gets if this property is considered "advanced" and should be hidden by default in a property grid.
/// </summary>
public bool IsAdvanced {
get { return propertyInfo.IsAdvanced; }
}
/// <summary>
/// Gets the dependency property.
/// </summary>
public DependencyProperty DependencyProperty {
get {
return propertyInfo.DependencyProperty;
}
}
void PossiblyNameChanged(XamlPropertyValue oldValue, XamlPropertyValue newValue)
{
if (ParentObject.RuntimeNameProperty != null && PropertyName == ParentObject.RuntimeNameProperty) {
if (!String.IsNullOrEmpty(ParentObject.GetXamlAttribute("Name"))) {
throw new XamlLoadException("The property 'Name' is set more than once.");
}
string oldName = null;
string newName = null;
var oldTextValue = oldValue as XamlTextValue;
if (oldTextValue != null) oldName = oldTextValue.Text;
var newTextValue = newValue as XamlTextValue;
if (newTextValue != null) newName = newTextValue.Text;
NameScopeHelper.NameChanged(ParentObject, oldName, newName);
}
}
/*public bool IsAttributeSyntax {
get {
return attribute != null;
}
}
public bool IsElementSyntax {
get {
return element != null;
}
}
public bool IsImplicitDefaultProperty {
get {
return attribute == null && element == null;
}
}*/
}
}

Loading…
Cancel
Save