diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/DependencyPropertyDotButton.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/DependencyPropertyDotButton.cs
index 0ae05116ee..3d2bb659fc 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/DependencyPropertyDotButton.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/DependencyPropertyDotButton.cs
@@ -6,6 +6,8 @@
//
using System;
+using System.ComponentModel;
+using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
@@ -18,14 +20,6 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
///
public class DependencyPropertyDotButton : ButtonBase
{
- /*
- ///
- /// Dependency property for .
- ///
- public static readonly DependencyProperty DataPropertyProperty
- = DependencyProperty.Register("DataProperty", typeof(IPropertyEditorDataProperty), typeof(DependencyPropertyDotButton));
- */
-
///
/// Dependency property for .
///
@@ -33,21 +27,56 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
= DependencyProperty.Register("Checked", typeof(bool), typeof(DependencyPropertyDotButton),
new FrameworkPropertyMetadata(false));
-
static DependencyPropertyDotButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DependencyPropertyDotButton), new FrameworkPropertyMetadata(typeof(DependencyPropertyDotButton)));
}
- /*
///
- /// Gets/Sets the property the button is used for.
+ /// Creates a new DependencyPropertyDotButton instance.
+ ///
+ public DependencyPropertyDotButton()
+ {
+ }
+
+ IPropertyEditorDataProperty property;
+
+ bool isIsSetChangedEventHandlerAttached;
+
+ ///
+ /// Creates a new DependencyPropertyDotButton instance that binds its Checked property to the
+ /// data properties IsSet property.
+ ///
+ public DependencyPropertyDotButton(IPropertyEditorDataProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+ this.property = property;
+
+ this.Loaded += delegate {
+ if (!isIsSetChangedEventHandlerAttached) {
+ isIsSetChangedEventHandlerAttached = true;
+ this.property.IsSetChanged += OnIsSetChanged;
+ OnIsSetChanged(null, null);
+ }
+ };
+ this.Unloaded += delegate {
+ if (isIsSetChangedEventHandlerAttached) {
+ isIsSetChangedEventHandlerAttached = false;
+ this.property.IsSetChanged -= OnIsSetChanged;
+ }
+ };
+ OnIsSetChanged(null, null);
+ }
+
+ ///
+ /// Creates the context menu on-demand.
///
- public IPropertyEditorDataProperty DataProperty {
- get { return (IPropertyEditorDataProperty)GetValue(DataPropertyProperty); }
- set { SetValue(DataPropertyProperty, value); }
+ protected override void OnContextMenuOpening(ContextMenuEventArgs e)
+ {
+ ContextMenu = CreateContextMenu();
+ base.OnContextMenuOpening(e);
}
- */
///
/// Gets/Sets if the button looks checked.
@@ -57,15 +86,48 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
set { SetValue(CheckedProperty, value); }
}
+ void OnIsSetChanged(object sender, EventArgs e)
+ {
+ this.Checked = property.IsSet;
+ }
+
///
/// Fires the Click event and opens the context menu.
///
protected override void OnClick()
{
base.OnClick();
- if (ContextMenu != null) {
- ContextMenu.IsOpen = true;
+ ContextMenu = CreateContextMenu();
+ ContextMenu.IsOpen = true;
+ }
+
+ internal ContextMenu CreateContextMenu()
+ {
+ ContextMenu contextMenu = new ContextMenu();
+ if (property.IsSet) {
+ contextMenu.Items.Add(CreateMenuItem("_Reset", OnResetClick));
+ } else {
+ contextMenu.Items.Add(CreateMenuItem("_Copy to local", OnCopyToLocalClick));
}
+ return contextMenu;
+ }
+
+ MenuItem CreateMenuItem(string title, RoutedEventHandler handler)
+ {
+ MenuItem item = new MenuItem();
+ item.Header = title;
+ item.Click += handler;
+ return item;
+ }
+
+ void OnResetClick(object sender, RoutedEventArgs e)
+ {
+ property.IsSet = false;
+ }
+
+ void OnCopyToLocalClick(object sender, RoutedEventArgs e)
+ {
+ property.IsSet = true;
}
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyEditor.cs
index 40a34399cd..4aa400da03 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyEditor.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyEditor.cs
@@ -51,10 +51,6 @@ namespace ICSharpCode.WpfDesign.Designer
Debug.WriteLine(ex.ToString());
throw;
}
- PropertyEditorCategoryView v = new PropertyEditorCategoryView();
- v.Header = "Titel";
- v.Content = "Inhalt";
- contentStackPanel.Children.Add(v);
}
///
@@ -66,7 +62,7 @@ namespace ICSharpCode.WpfDesign.Designer
}
///
- /// Is raised when the object being edited changes.
+ /// Is raised when the value of the property changes.
///
public event EventHandler EditedObjectChanged;
@@ -101,6 +97,9 @@ namespace ICSharpCode.WpfDesign.Designer
List categories = new List();
foreach (IPropertyEditorDataProperty p in Linq.Sort(dataSource.Properties, ComparePropertyNames)) {
+ if (p.Name == "Name") {
+ continue;
+ }
PropertyEditorCategoryView cv = GetOrCreateCategory(categories, p.Category);
PropertyGridView grid = (PropertyGridView)cv.Content;
grid.AddProperty(p);
@@ -120,7 +119,9 @@ namespace ICSharpCode.WpfDesign.Designer
return p1.Name.CompareTo(p2.Name);
}
- static PropertyEditorCategoryView GetOrCreateCategory(List categories, string category)
+ HashSet expandedCategories = new HashSet();
+
+ PropertyEditorCategoryView GetOrCreateCategory(List categories, string category)
{
foreach (PropertyEditorCategoryView c in categories) {
if (c.Header.ToString() == category)
@@ -129,6 +130,13 @@ namespace ICSharpCode.WpfDesign.Designer
PropertyEditorCategoryView newCategory = new PropertyEditorCategoryView();
newCategory.Header = category;
newCategory.Content = new PropertyGridView();
+ newCategory.IsExpanded = expandedCategories.Contains(category);
+ newCategory.Expanded += delegate {
+ expandedCategories.Add(category);
+ };
+ newCategory.Collapsed += delegate {
+ expandedCategories.Remove(category);
+ };
categories.Add(newCategory);
return newCategory;
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyGridView.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyGridView.cs
index 74054656e8..e97b852f02 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyGridView.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyGridView.cs
@@ -7,6 +7,7 @@
using System;
using System.Windows;
+using System.Windows.Documents;
using System.Windows.Data;
using System.Windows.Controls;
using ICSharpCode.WpfDesign.PropertyEditor;
@@ -31,9 +32,9 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
this.ColumnDefinitions.Add(new ColumnDefinition());
this.ColumnDefinitions.Add(new ColumnDefinition());
this.ColumnDefinitions.Add(new ColumnDefinition());
- this.ColumnDefinitions[0].Width = new GridLength(0.45, GridUnitType.Star);
+ this.ColumnDefinitions[0].Width = new GridLength(0.48, GridUnitType.Star);
this.ColumnDefinitions[0].MinWidth = 40;
- this.ColumnDefinitions[1].Width = new GridLength(0.55, GridUnitType.Star);
+ this.ColumnDefinitions[1].Width = new GridLength(0.52, GridUnitType.Star);
this.ColumnDefinitions[2].Width = new GridLength(16);
}
@@ -44,22 +45,27 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
{
this.RowDefinitions.Add(new RowDefinition());
- Label propertyNameLabel = new Label();
- propertyNameLabel.Content = property.Name;
- propertyNameLabel.HorizontalContentAlignment = HorizontalAlignment.Right;
- SetRow(propertyNameLabel, this.RowDefinitions.Count - 1);
- SetColumn(propertyNameLabel, 0);
- this.Children.Add(propertyNameLabel);
+ // Column 0: name of the property
+ PropertyNameTextBlock propertyNameText = new PropertyNameTextBlock(property);
+ propertyNameText.Margin = new Thickness(0, 0, 2, 0);
+ SetRow(propertyNameText, this.RowDefinitions.Count - 1);
+ SetColumn(propertyNameText, 0);
+ this.Children.Add(propertyNameText);
- DependencyPropertyDotButton dotButton = new DependencyPropertyDotButton();
+ // Column 1: the actual property editor
+ UIElement editor = property.CreateEditor();
+ SetRow(editor, this.RowDefinitions.Count - 1);
+ SetColumn(editor, 1);
+ this.Children.Add(editor);
+
+ // Column 2: a "dot" button
+ DependencyPropertyDotButton dotButton = new DependencyPropertyDotButton(property);
dotButton.VerticalAlignment = VerticalAlignment.Center;
dotButton.HorizontalAlignment = HorizontalAlignment.Center;
- Binding binding = new Binding("IsSet");
- binding.Source = property;
- dotButton.SetBinding(DependencyPropertyDotButton.CheckedProperty, binding);
SetRow(dotButton, this.RowDefinitions.Count - 1);
SetColumn(dotButton, 2);
this.Children.Add(dotButton);
+ propertyNameText.ContextMenuProvider = dotButton;
}
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyNameTextBlock.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyNameTextBlock.cs
new file mode 100644
index 0000000000..a6b36523cb
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/PropertyEditor/PropertyNameTextBlock.cs
@@ -0,0 +1,65 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using ICSharpCode.WpfDesign.PropertyEditor;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls
+{
+ // Text block used in the first column of the PropertyGridView.
+ // Creates ToolTip and ContextMenu objects on-demand.
+ sealed class PropertyNameTextBlock : TextBlock
+ {
+ readonly IPropertyEditorDataProperty property;
+ readonly TextBlock toolTipTextBlock;
+ bool toolTipTextBlockInitialized;
+ internal DependencyPropertyDotButton ContextMenuProvider;
+
+ public PropertyNameTextBlock(IPropertyEditorDataProperty property)
+ : base(new Run(property.Name))
+ {
+ this.property = property;
+ this.TextAlignment = TextAlignment.Right;
+ this.TextTrimming = TextTrimming.CharacterEllipsis;
+
+ this.ToolTip = toolTipTextBlock = new TextBlock();
+ }
+
+ protected override void OnToolTipOpening(ToolTipEventArgs e)
+ {
+ CreateToolTip();
+ base.OnToolTipOpening(e);
+ }
+
+ protected override void OnContextMenuOpening(ContextMenuEventArgs e)
+ {
+ if (ContextMenuProvider != null) {
+ this.ContextMenu = ContextMenuProvider.CreateContextMenu();
+ }
+ base.OnContextMenuOpening(e);
+ }
+
+ void CreateToolTip()
+ {
+ if (toolTipTextBlockInitialized)
+ return;
+ toolTipTextBlockInitialized = true;
+ toolTipTextBlock.TextAlignment = TextAlignment.Left;
+ toolTipTextBlock.Inlines.Add(new Bold(new Run(property.Name)));
+ if (property.ReturnType != null) {
+ toolTipTextBlock.Inlines.Add(" (" + property.ReturnType.Name + ")");
+ }
+ if (!string.IsNullOrEmpty(property.Description)) {
+ toolTipTextBlock.Inlines.Add(new LineBreak());
+ toolTipTextBlock.Inlines.Add(property.Description);
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs
new file mode 100644
index 0000000000..0ff5e90265
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs
@@ -0,0 +1,35 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Media;
+using ICSharpCode.WpfDesign.PropertyEditor;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors
+{
+ ///
+ /// Type editor used to edit Brush properties.
+ ///
+ [TypeEditor(typeof(Brush))]
+ public sealed class BrushEditor : Border
+ {
+ ///
+ /// Creates a new BooleanEditor instance.
+ ///
+ public BrushEditor(IPropertyEditorDataProperty property)
+ {
+ this.BorderBrush = Brushes.Black;
+ this.BorderThickness = new Thickness(1);
+ SetBinding(BackgroundProperty, PropertyEditorBindingHelper.CreateBinding(this, property));
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/WindowClone.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/WindowClone.cs
index aee96b4f70..690710080e 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/WindowClone.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/WindowClone.cs
@@ -119,7 +119,8 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
}
///
- /// A for .
+ /// A for
+ /// (and derived classes, unless they specify their own ).
///
[ExtensionFor(typeof(Window))]
public class WindowCloneExtension : CustomInstanceFactory
@@ -130,7 +131,6 @@ namespace ICSharpCode.WpfDesign.Designer.Controls
public override object CreateInstance(Type type, params object[] arguments)
{
Debug.Assert(arguments.Length == 0);
- Debug.Assert(type == typeof(Window));
return new WindowClone();
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
index b2e2069ac6..f010cc2f57 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
@@ -62,8 +62,10 @@
+
+
@@ -86,6 +88,7 @@
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
index fb8fe68835..c4f1151bdd 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
@@ -10,6 +10,7 @@ using System.Xml;
using ICSharpCode.WpfDesign.XamlDom;
using ICSharpCode.WpfDesign.Designer.Services;
using ICSharpCode.WpfDesign.Extensions;
+using ICSharpCode.WpfDesign.PropertyEditor;
namespace ICSharpCode.WpfDesign.Designer.Xaml
{
@@ -42,8 +43,12 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
_componentService = new XamlComponentService(this);
this.Services.AddService(typeof(IComponentService), _componentService);
+ EditorManager propertyGridEditorManager = new EditorManager();
+ this.Services.AddService(typeof(EditorManager), propertyGridEditorManager);
+
// register extensions from this assembly:
this.Services.ExtensionManager.RegisterAssembly(typeof(XamlDesignContext).Assembly);
+ propertyGridEditorManager.RegisterAssembly(typeof(XamlDesignContext).Assembly);
XamlParserSettings xamlParseSettings = new XamlParserSettings();
xamlParseSettings.CreateInstanceCallback = OnXamlParserCreateInstance;
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs
index 4890a7e73d..28f17f218f 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignItem.cs
@@ -5,6 +5,9 @@
// $Revision$
//
+// enable this define to test that event handlers are removed correctly
+//#define EventHandlerDebugging
+
using System;
using System.Diagnostics;
using System.Windows;
@@ -48,12 +51,24 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
set { throw new NotImplementedException(); }
}
+ #if EventHandlerDebugging
+ static int totalEventHandlerCount;
+ #endif
+
///
/// Is raised when the name of the design item changes.
///
public override event EventHandler NameChanged {
- add { Debug.WriteLine("Add event handler to " + this.Component.GetType().Name); }
- remove { Debug.WriteLine("Remove event handler from " + this.Component.GetType().Name); }
+ add {
+ #if EventHandlerDebugging
+ Debug.WriteLine("Add event handler to " + this.Component.GetType().Name + " (handler count=" + (++totalEventHandlerCount) + ")");
+ #endif
+ }
+ remove {
+ #if EventHandlerDebugging
+ Debug.WriteLine("Remove event handler from " + this.Component.GetType().Name + " (handler count=" + (--totalEventHandlerCount) + ")");
+ #endif
+ }
}
public override DesignItem Parent {
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs
index 639be84160..7b5ff8baf9 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlModelProperty.cs
@@ -5,6 +5,9 @@
// $Revision$
//
+// Turn this on to ensure event handlers on model properties are removed correctly:
+#define EventHandlerDebugging
+
using System;
using System.Diagnostics;
using ICSharpCode.WpfDesign.XamlDom;
@@ -48,6 +51,18 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
get { return _property.IsCollection; }
}
+ public override Type ReturnType {
+ get { return _property.ReturnType; }
+ }
+
+ public override Type DeclaringType {
+ get { return _property.PropertyTargetType; }
+ }
+
+ public override System.ComponentModel.TypeConverter TypeConverter {
+ get { return _property.TypeConverter; }
+ }
+
public override System.Collections.Generic.IList CollectionElements {
get {
throw new NotImplementedException();
@@ -69,23 +84,65 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
}
}
- public override object ValueOnInstance {
- get {
- return _property.ValueOnInstance;
+ public override event EventHandler ValueChanged {
+ add {
+ #if EventHandlerDebugging
+ if (ValueChangedEventHandlers == 0) {
+ Debug.WriteLine("ValueChangedEventHandlers is now > 0");
+ }
+ ValueChangedEventHandlers++;
+ #endif
+ _property.ValueChanged += value;
}
- set {
- _property.ValueOnInstance = value;
+ remove {
+ #if EventHandlerDebugging
+ ValueChangedEventHandlers--;
+ if (ValueChangedEventHandlers == 0) {
+ Debug.WriteLine("ValueChangedEventHandlers reached 0");
+ }
+ #endif
+ _property.ValueChanged -= value;
}
}
+ public override object ValueOnInstance {
+ get { return _property.ValueOnInstance; }
+ set { _property.ValueOnInstance = value; }
+ }
+
public override bool IsSet {
- get {
- return _property.IsSet;
+ get { return _property.IsSet; }
+ }
+
+ #if EventHandlerDebugging
+ static int IsSetChangedEventHandlers, ValueChangedEventHandlers;
+ #endif
+
+ public override event EventHandler IsSetChanged {
+ add {
+ #if EventHandlerDebugging
+ if (IsSetChangedEventHandlers == 0) {
+ Debug.WriteLine("IsSetChangedEventHandlers is now > 0");
+ }
+ IsSetChangedEventHandlers++;
+ #endif
+ _property.IsSetChanged += value;
+ }
+ remove {
+ #if EventHandlerDebugging
+ IsSetChangedEventHandlers--;
+ if (IsSetChangedEventHandlers == 0) {
+ Debug.WriteLine("IsSetChangedEventHandlers reached 0");
+ }
+ #endif
+ _property.IsSetChanged -= value;
}
}
public override void SetValue(object value)
{
+ _property.ValueOnInstance = value;
+
XamlComponentService componentService = _designItem.ComponentService;
XamlDesignItem designItem = (XamlDesignItem)componentService.GetDesignItem(value);
@@ -98,8 +155,6 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
designItem = componentService.RegisterXamlComponentRecursive(val as XamlObject);
_property.PropertyValue = val;
}
-
- _property.ValueOnInstance = value;
}
public override void Reset()
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
index bd4f8df977..303f78024b 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
@@ -10,6 +10,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
+using System.Windows;
using System.Windows.Markup;
using System.Xml;
@@ -280,7 +281,10 @@ namespace ICSharpCode.WpfDesign.XamlDom
MethodInfo getMethod = elementType.GetMethod("Get" + propertyName, BindingFlags.Public | BindingFlags.Static);
MethodInfo setMethod = elementType.GetMethod("Set" + propertyName, BindingFlags.Public | BindingFlags.Static);
if (getMethod != null && setMethod != null) {
- return new XamlAttachedPropertyInfo(getMethod, setMethod, propertyName);
+ FieldInfo field = elementType.GetField(propertyName + "Property", BindingFlags.Public | BindingFlags.Static);
+ if (field != null && field.FieldType == typeof(DependencyProperty)) {
+ return new XamlDependencyPropertyInfo((DependencyProperty)field.GetValue(null), true);
+ }
}
return null;
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs
index 51bbf6fbbe..840346dab5 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs
@@ -73,6 +73,20 @@ namespace ICSharpCode.WpfDesign.XamlDom
get { return propertyInfo.TargetType; }
}
+ ///
+ /// Gets the return type of the property.
+ ///
+ public Type ReturnType {
+ get { return propertyInfo.ReturnType; }
+ }
+
+ ///
+ /// Gets the type converter used to convert property values to/from string.
+ ///
+ public TypeConverter TypeConverter {
+ get { return propertyInfo.TypeConverter; }
+ }
+
///
/// Gets the value of the property. Can be null if the property is a collection property.
///
@@ -82,10 +96,21 @@ namespace ICSharpCode.WpfDesign.XamlDom
if (IsCollection)
throw new InvalidOperationException();
- Reset();
+ bool wasSet = this.IsSet;
+
+ ResetInternal();
propertyValue = value;
propertyValue.AddNodeTo(this);
propertyValue.ParentProperty = this;
+
+ if (!wasSet) {
+ if (IsSetChanged != null) {
+ IsSetChanged(this, EventArgs.Empty);
+ }
+ }
+ if (ValueChanged != null) {
+ ValueChanged(this, EventArgs.Empty);
+ }
}
}
@@ -129,10 +154,36 @@ namespace ICSharpCode.WpfDesign.XamlDom
get { return propertyValue != null || collectionElements != null; }
}
+ ///
+ /// Occurs when the value of the IsSet property has changed.
+ ///
+ public event EventHandler IsSetChanged;
+
+ ///
+ /// Occurs when the value of the property has changed.
+ ///
+ public event EventHandler ValueChanged;
+
///
/// Resets the properties value.
///
public void Reset()
+ {
+ if (IsSet) {
+ propertyInfo.ResetValue(parentObject.Instance);
+
+ ResetInternal();
+
+ if (IsSetChanged != null) {
+ IsSetChanged(this, EventArgs.Empty);
+ }
+ if (ValueChanged != null) {
+ ValueChanged(this, EventArgs.Empty);
+ }
+ }
+ }
+
+ void ResetInternal()
{
if (propertyValue != null) {
propertyValue.RemoveNodeFromParent();
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs
index be53553c26..b2957b95bf 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs
@@ -6,10 +6,12 @@
//
using System;
+using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
+using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
@@ -22,8 +24,10 @@ namespace ICSharpCode.WpfDesign.XamlDom
{
public abstract object GetValue(object instance);
public abstract void SetValue(object instance, object value);
+ public abstract void ResetValue(object instance);
public abstract TypeConverter TypeConverter { get; }
public abstract Type TargetType { get; }
+ public abstract Type ReturnType { get; }
public abstract string Name { get; }
public abstract string FullyQualifiedName { get; }
public abstract bool IsAttached { get; }
@@ -31,41 +35,44 @@ namespace ICSharpCode.WpfDesign.XamlDom
internal abstract void AddValue(object collectionInstance, XamlPropertyValue newElement);
}
- internal sealed class XamlAttachedPropertyInfo : XamlPropertyInfo
+ internal class XamlDependencyPropertyInfo : XamlPropertyInfo
{
- MethodInfo _getMethod;
- MethodInfo _setMethod;
- string _name;
+ readonly DependencyProperty property;
+ readonly bool isAttached;
- public XamlAttachedPropertyInfo(MethodInfo getMethod, MethodInfo setMethod, string name)
+ public XamlDependencyPropertyInfo(DependencyProperty property, bool isAttached)
{
- this._getMethod = getMethod;
- this._setMethod = setMethod;
- this._name = name;
+ Debug.Assert(property != null);
+ this.property = property;
+ this.isAttached = isAttached;
}
public override TypeConverter TypeConverter {
get {
- return TypeDescriptor.GetConverter(_getMethod.ReturnType);
+ return TypeDescriptor.GetConverter(this.ReturnType);
}
}
public override string FullyQualifiedName {
get {
- return _getMethod.DeclaringType.FullName + "." + _name;
+ return this.TargetType.FullName + "." + this.Name;
}
}
public override Type TargetType {
- get { return _getMethod.DeclaringType; }
+ get { return property.OwnerType; }
+ }
+
+ public override Type ReturnType {
+ get { return property.PropertyType; }
}
public override string Name {
- get { return _name; }
+ get { return property.Name; }
}
public override bool IsAttached {
- get { return true; }
+ get { return isAttached; }
}
public override bool IsCollection {
@@ -74,12 +81,17 @@ namespace ICSharpCode.WpfDesign.XamlDom
public override object GetValue(object instance)
{
- return _getMethod.Invoke(null, new object[] { instance });
+ return ((DependencyObject)instance).GetValue(property);
}
public override void SetValue(object instance, object value)
{
- _setMethod.Invoke(null, new object[] { instance, value });
+ ((DependencyObject)instance).SetValue(property, value);
+ }
+
+ public override void ResetValue(object instance)
+ {
+ ((DependencyObject)instance).ClearValue(property);
}
internal override void AddValue(object collectionInstance, XamlPropertyValue newElement)
@@ -107,6 +119,15 @@ namespace ICSharpCode.WpfDesign.XamlDom
_propertyDescriptor.SetValue(instance, value);
}
+ public override void ResetValue(object instance)
+ {
+ _propertyDescriptor.ResetValue(instance);
+ }
+
+ public override Type ReturnType {
+ get { return _propertyDescriptor.PropertyType; }
+ }
+
public override Type TargetType {
get { return _propertyDescriptor.ComponentType; }
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs
index b6f741bf9e..ad2f06bb70 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItemProperty.cs
@@ -8,6 +8,7 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Windows;
namespace ICSharpCode.WpfDesign
@@ -25,6 +26,23 @@ namespace ICSharpCode.WpfDesign
///
public abstract string Name { get; }
+ ///
+ /// Gets the return type of the property.
+ ///
+ public abstract Type ReturnType { get; }
+
+ ///
+ /// Gets the type that declares the property.
+ ///
+ public abstract Type DeclaringType { get; }
+
+ ///
+ /// Gets the type converter used to convert property values to/from string.
+ ///
+ public virtual TypeConverter TypeConverter {
+ get { return TypeDescriptor.GetConverter(this.ReturnType); }
+ }
+
///
/// Gets if the property represents a collection.
///
@@ -36,10 +54,16 @@ namespace ICSharpCode.WpfDesign
public abstract IList CollectionElements { get; }
///
- /// Gets the value of the property. This property returns null if the value is not set.
+ /// Gets the value of the property. This property returns null if the value is not set,
+ /// or if the value is set to a primitive value.
///
public abstract DesignItem Value { get; }
+ ///
+ /// Is raised when the value of the property changes (by calling or ).
+ ///
+ public abstract event EventHandler ValueChanged;
+
///
/// Gets/Sets the value of the property on the designed instance.
/// If the property is not set, this returns the default value.
@@ -57,6 +81,11 @@ namespace ICSharpCode.WpfDesign
///
public abstract bool IsSet { get; }
+ ///
+ /// Occurs when the value of the IsSet property changes.
+ ///
+ public abstract event EventHandler IsSetChanged;
+
///
/// Resets the property value to the default, possibly removing it from the list of properties.
///
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/BooleanEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/BooleanEditor.cs
new file mode 100644
index 0000000000..93b6f1c75e
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/BooleanEditor.cs
@@ -0,0 +1,30 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Controls;
+using System.Windows.Documents;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Type editor used to edit bool properties.
+ ///
+ sealed class BooleanEditor : CheckBox
+ {
+ ///
+ /// Creates a new BooleanEditor instance.
+ ///
+ public BooleanEditor(IPropertyEditorDataProperty property)
+ {
+ SetBinding(IsCheckedProperty, PropertyEditorBindingHelper.CreateBinding(this, property));
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataProperty.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataProperty.cs
index 62d8f17ef7..015401c4f2 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataProperty.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataProperty.cs
@@ -7,6 +7,7 @@
using System;
using System.Diagnostics;
+using System.Windows;
namespace ICSharpCode.WpfDesign.PropertyEditor
{
@@ -43,6 +44,10 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
get { return "Description for " + property.Name; }
}
+ public System.ComponentModel.TypeConverter TypeConverter {
+ get { return property.TypeConverter; }
+ }
+
public bool IsSet {
get {
return property.IsSet;
@@ -59,6 +64,11 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
}
}
+ public event EventHandler IsSetChanged {
+ add { property.IsSetChanged += value; }
+ remove { property.IsSetChanged -= value; }
+ }
+
public object Value {
get {
return property.ValueOnInstance;
@@ -68,6 +78,25 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
}
}
+ public event EventHandler ValueChanged {
+ add { property.ValueChanged += value; }
+ remove { property.ValueChanged -= value; }
+ }
+
+ ///
+ /// Gets the type of the property value.
+ ///
+ public Type ReturnType {
+ get { return property.ReturnType; }
+ }
+
+ ///
+ /// Gets the type that declares the property.
+ ///
+ public Type DeclaringType {
+ get { return property.DeclaringType; }
+ }
+
public bool CanUseCustomExpression {
get {
return true;
@@ -78,5 +107,18 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
{
throw new NotImplementedException();
}
+
+ ///
+ /// Creates a UIElement that can edit the property value.
+ ///
+ public UIElement CreateEditor()
+ {
+ EditorManager manager = ownerDataSource.DesignItem.Services.GetService();
+ if (manager != null) {
+ return manager.CreateEditor(this);
+ } else {
+ return new FallbackEditor(this);
+ }
+ }
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataSource.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataSource.cs
index 791dbba2b9..a3e198e1f2 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataSource.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/DesignItemDataSource.cs
@@ -54,6 +54,12 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
return item.GetBehavior() ?? new DesignItemDataSource(item);
}
+ ///
+ /// Gets the design item for which this DesignItemDataSource was created.
+ ///
+ public DesignItem DesignItem {
+ get { return item; }
+ }
/// See
public string Name {
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs
new file mode 100644
index 0000000000..a686c2ce67
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EditorManager.cs
@@ -0,0 +1,111 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Windows;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Manages registered type and property editors.
+ ///
+ public sealed class EditorManager
+ {
+ // property return type => editor type
+ Dictionary _typeEditors = new Dictionary();
+ // property full name => editor type
+ Dictionary _propertyEditors = new Dictionary();
+
+ ///
+ /// Creates an editor for the specified property.
+ ///
+ public UIElement CreateEditor(IPropertyEditorDataProperty property)
+ {
+ return (UIElement)Activator.CreateInstance(GetEditorType(property), property);
+ }
+
+ ///
+ /// Creates the fallback editor for the specified property.
+ ///
+ public static UIElement CreateFallbackEditor(IPropertyEditorDataProperty property)
+ {
+ return (UIElement)Activator.CreateInstance(GetFallbackEditorType(property), property);
+ }
+
+ ///
+ /// Gets the type of the editor that can edit the specified property.
+ ///
+ public Type GetEditorType(IPropertyEditorDataProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ Type editorType;
+ if (_propertyEditors.TryGetValue(property.DeclaringType.FullName + "." + property.Name, out editorType))
+ return editorType;
+ else if (_typeEditors.TryGetValue(property.ReturnType, out editorType))
+ return editorType;
+ else
+ return GetFallbackEditorType(property);
+ }
+
+ ///
+ /// Gets the type of the fallback editor used for the specified property.
+ ///
+ public static Type GetFallbackEditorType(IPropertyEditorDataProperty property)
+ {
+ Type returnType = property.ReturnType;
+ if (returnType.IsEnum) {
+ return typeof(EnumEditor);
+ } else if (returnType == typeof(bool)) {
+ return typeof(BooleanEditor);
+ } else {
+ TypeConverter c = property.TypeConverter;
+ if (c != null && c.CanConvertFrom(typeof(string)) && c.CanConvertTo(typeof(string)))
+ return typeof(TextBoxEditor);
+ else
+ return typeof(FallbackEditor);
+ }
+ }
+
+ ///
+ /// Registers property editors defined in the specified assembly.
+ ///
+ public void RegisterAssembly(Assembly assembly)
+ {
+ if (assembly == null)
+ throw new ArgumentNullException("assembly");
+
+ foreach (Type type in assembly.GetExportedTypes()) {
+ foreach (TypeEditorAttribute editorAttribute in type.GetCustomAttributes(typeof(TypeEditorAttribute), false)) {
+ CheckValidEditor(type);
+ _typeEditors[editorAttribute.SupportedPropertyType] = type;
+ }
+ foreach (PropertyEditorAttribute editorAttribute in type.GetCustomAttributes(typeof(PropertyEditorAttribute), false)) {
+ CheckValidEditor(type);
+ string propertyName = editorAttribute.PropertyDeclaringType.FullName + "." + editorAttribute.PropertyName;
+ _propertyEditors[propertyName] = type;
+ }
+ }
+ }
+
+ static readonly Type[] typeArrayWithPropertyEditorDataProperty = { typeof(IPropertyEditorDataProperty) };
+
+ static void CheckValidEditor(Type type)
+ {
+ if (!typeof(UIElement).IsAssignableFrom(type)) {
+ throw new DesignerException("Editor types must derive from UIElement!");
+ }
+ if (type.GetConstructor(typeArrayWithPropertyEditorDataProperty) == null) {
+ throw new DesignerException("Editor types must have a constructor that takes a IPropertyEditorDataProperty as argument!");
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EnumEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EnumEditor.cs
new file mode 100644
index 0000000000..d974084722
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/EnumEditor.cs
@@ -0,0 +1,31 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Media;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Type editor used to edit enum properties.
+ ///
+ sealed class EnumEditor : ComboBox
+ {
+ ///
+ /// Creates a new EnumEditor instance.
+ ///
+ public EnumEditor(IPropertyEditorDataProperty property)
+ {
+
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/FallbackEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/FallbackEditor.cs
new file mode 100644
index 0000000000..5dfa34d6e9
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/FallbackEditor.cs
@@ -0,0 +1,50 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// The type editor used when no other type editor could be found.
+ ///
+ [TypeEditor(typeof(object))]
+ public sealed class FallbackEditor : TextBlock
+ {
+ ///
+ /// Creates a new FallbackEditor instance for the specified property.
+ ///
+ public FallbackEditor(IPropertyEditorDataProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ this.TextTrimming = TextTrimming.CharacterEllipsis;
+ if (property.IsSet) {
+ this.FontWeight = FontWeights.Bold;
+ }
+ object val = property.Value;
+ if (val == null) {
+ this.Text = "null";
+ this.FontStyle = FontStyles.Italic;
+ } else {
+ try {
+ this.Text = val.ToString();
+ } catch (Exception ex) {
+ this.FontWeight = FontWeights.Regular;
+ Inlines.Add(new Italic(new Run(ex.GetType().Name)));
+ Inlines.Add(" ");
+ Inlines.Add(ex.Message);
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/IPropertyEditorDataSource.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/IPropertyEditorDataSource.cs
index 240e316fc9..d9d0d3c6d9 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/IPropertyEditorDataSource.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/IPropertyEditorDataSource.cs
@@ -9,6 +9,8 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Media;
+using System.Windows;
+
namespace ICSharpCode.WpfDesign.PropertyEditor
{
///
@@ -21,6 +23,11 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
///
string Name { get; set; }
+ ///
+ /// Is raised whenever the Name property changes value.
+ ///
+ event EventHandler NameChanged;
+
///
/// Gets the type of the item (for display only).
///
@@ -62,6 +69,21 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
///
string Name { get; }
+ ///
+ /// Gets the type of the property value.
+ ///
+ Type ReturnType { get; }
+
+ ///
+ /// Gets the type that declares the property.
+ ///
+ Type DeclaringType { get; }
+
+ ///
+ /// Gets the type converter used to convert property values to/from string.
+ ///
+ TypeConverter TypeConverter { get; }
+
///
/// Gets the description of the property.
///
@@ -74,11 +96,21 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
///
bool IsSet { get; set; }
+ ///
+ /// Is raised when the IsSet property has changed.
+ ///
+ event EventHandler IsSetChanged;
+
///
/// Gets/Sets the value of the property.
///
object Value { get; set; }
+ ///
+ /// Is raised when the Value property has changed.
+ ///
+ event EventHandler ValueChanged;
+
///
/// Gets if using a custom expression is supported.
///
@@ -88,5 +120,10 @@ namespace ICSharpCode.WpfDesign.PropertyEditor
/// Sets a custom expression.
///
void SetCustomExpression(string expression);
+
+ ///
+ /// Creates a UIElement that can edit the property value.
+ ///
+ UIElement CreateEditor();
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorAttribute.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorAttribute.cs
new file mode 100644
index 0000000000..22de895fae
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorAttribute.cs
@@ -0,0 +1,50 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Attribute to specify that the decorated class is a editor for the specified property.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
+ public sealed class PropertyEditorAttribute : Attribute
+ {
+ readonly Type propertyDeclaringType;
+ readonly string propertyName;
+
+ ///
+ /// Creates a new PropertyEditorAttribute that specifies that the decorated class is a editor
+ /// for the ".".
+ ///
+ public PropertyEditorAttribute(Type propertyDeclaringType, string propertyName)
+ {
+ if (propertyDeclaringType == null)
+ throw new ArgumentNullException("propertyDeclaringType");
+ if (propertyName == null)
+ throw new ArgumentNullException("propertyName");
+ this.propertyDeclaringType = propertyDeclaringType;
+ this.propertyName = propertyName;
+ }
+
+ ///
+ /// Gets the type that declares the property that the decorated editor supports.
+ ///
+ public Type PropertyDeclaringType {
+ get { return propertyDeclaringType; }
+ }
+
+ ///
+ /// Gets the name of the property that the decorated editor supports.
+ ///
+ public string PropertyName {
+ get { return propertyName; }
+ }
+ }
+}
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs
new file mode 100644
index 0000000000..a8274b6b56
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/PropertyEditorBindingHelper.cs
@@ -0,0 +1,79 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+using System.ComponentModel;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Provides a static method to create a binding between a dependency property
+ /// and a data property.
+ ///
+ public static class PropertyEditorBindingHelper
+ {
+ ///
+ /// Binds editor.property to dataProperty.Value.
+ ///
+ public static Binding CreateBinding(FrameworkElement editor, IPropertyEditorDataProperty dataProperty)
+ {
+ if (editor == null)
+ throw new ArgumentNullException("editor");
+ if (dataProperty == null)
+ throw new ArgumentNullException("dataProperty");
+
+ CustomBinding customBinding = new CustomBinding(dataProperty);
+ editor.Loaded += customBinding.OnLoaded;
+ editor.Unloaded += customBinding.OnUnloaded;
+ if (editor.IsLoaded) {
+ customBinding.OnLoaded(editor, null);
+ }
+
+ Binding b = new Binding("BoundValue");
+ b.Source = customBinding;
+ b.ConverterCulture = CultureInfo.InvariantCulture;
+ return b;
+ }
+
+ sealed class CustomBinding : INotifyPropertyChanged
+ {
+ readonly IPropertyEditorDataProperty dataProperty;
+
+ public CustomBinding(IPropertyEditorDataProperty dataProperty)
+ {
+ this.dataProperty = dataProperty;
+ }
+
+ internal void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ dataProperty.ValueChanged += OnValueChanged;
+ }
+
+ internal void OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ dataProperty.ValueChanged -= OnValueChanged;
+ }
+
+ public object BoundValue {
+ get { return dataProperty.Value; }
+ set { dataProperty.Value = value; }
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ void OnValueChanged(object sender, EventArgs e)
+ {
+ if (PropertyChanged != null) {
+ PropertyChanged(this, new PropertyChangedEventArgs("BoundValue"));
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TextBoxEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TextBoxEditor.cs
new file mode 100644
index 0000000000..48193170d1
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TextBoxEditor.cs
@@ -0,0 +1,54 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Media;
+using System.Windows.Controls;
+using System.Windows.Documents;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Type editor used to edit properties using a text box and the type's default type converter.
+ ///
+ sealed class TextBoxEditor : TextBox
+ {
+ ///
+ /// Creates a new TextBoxEditor instance.
+ ///
+ public TextBoxEditor(IPropertyEditorDataProperty property)
+ {
+ Binding b = PropertyEditorBindingHelper.CreateBinding(this, property);
+ b.Converter = new ToStringConverter(property.TypeConverter);
+ SetBinding(TextProperty, b);
+ }
+
+ sealed class ToStringConverter : IValueConverter
+ {
+ readonly TypeConverter converter;
+
+ public ToStringConverter(TypeConverter converter)
+ {
+ this.converter = converter;
+ }
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return converter.ConvertToString(null, culture, value);
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return converter.ConvertFromString(null, culture, (string)value);
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TypeEditorAttribute.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TypeEditorAttribute.cs
new file mode 100644
index 0000000000..34de52b96b
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/PropertyEditor/TypeEditorAttribute.cs
@@ -0,0 +1,39 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.WpfDesign.PropertyEditor
+{
+ ///
+ /// Attribute to specify that the decorated class is a editor for properties with the specified
+ /// return type.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
+ public sealed class TypeEditorAttribute : Attribute
+ {
+ readonly Type supportedPropertyType;
+
+ ///
+ /// Creates a new TypeEditorAttribute that specifies that the decorated class is a editor
+ /// for properties with the return type "".
+ ///
+ public TypeEditorAttribute(Type supportedPropertyType)
+ {
+ if (supportedPropertyType == null)
+ throw new ArgumentNullException("supportedPropertyType");
+ this.supportedPropertyType = supportedPropertyType;
+ }
+
+ ///
+ /// Gets the supported property type.
+ ///
+ public Type SupportedPropertyType {
+ get { return supportedPropertyType; }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
index 352b057e1c..a6ac387aae 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
@@ -79,10 +79,18 @@
+
+
+
+
+
+
+
+