This project is read-only.

use the property grid with .Net 4.0 WF Activities like this

Aug 5, 2010 at 12:46 AM
Edited Aug 31, 2010 at 3:39 PM

The WF engine with .Net 4 comes with a property grid. You can pull it out with reflection using code like that below.

Aug 6, 2010 at 12:06 AM
Edited Aug 31, 2010 at 3:47 PM

Round two of that idea:

using System;
using System.Activities.Presentation;
using System.Activities.Presentation.Model;
using System.Activities.Presentation.View;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace NS
{ /// /// WPF Native PropertyGrid class, taken from Workflow Foundation Designer /// public class PropertyGrid : UserControl { protected readonly MethodInfo _onSelectionChanged; protected readonly Grid _inspector; protected readonly ModelTreeManager _modelTreeManager = new ModelTreeManager(new EditingContext()); /// /// Default constructor, creates a hidden designer view and a property inspector /// public PropertyGrid() { var type = typeof(WorkflowDesigner).Assembly.GetType("System.Activities.Presentation.Internal.PropertyEditing.Metadata.PropertyInspectorMetadata"); type.GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public).Invoke(type, new object[0]); type = typeof(WorkflowDesigner).Assembly.GetType("System.Activities.Presentation.Internal.PropertyEditing.Resources.PropertyInspectorResources"); var resources = (ResourceDictionary)type.GetMethod("GetResources", BindingFlags.Static | BindingFlags.Public).Invoke(type, new object[0]); type = typeof(WorkflowDesigner).Assembly.GetType("System.Activities.Presentation.Internal.PropertyEditing.PropertyInspector"); _inspector = (Grid)type.GetConstructor(new Type[0]).Invoke(new object[0]); Resources.MergedDictionaries.Add(_inspector.Resources); _inspector.Resources.MergedDictionaries.Add(resources); _onSelectionChanged = type.GetMethod("OnSelectionChanged"); Content = _inspector; } public static readonly DependencyProperty SelectedObjectProperty = DependencyProperty.Register("SelectedObject", typeof(object), typeof(PropertyGrid), new PropertyMetadata(null, OnSelectedObjectChanged)); private static void OnSelectedObjectChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var pg = o as PropertyGrid; if (pg == null) return; // if we're a collection // select all objects in the collection // if we're an observable collection, listen for change and update our selection in that case // make sure that the grid updates with changes to dependency property properties on individual objects var objects = e.NewValue as IEnumerable ?? new[] { e.NewValue }; if (e.OldValue is INotifyCollectionChanged) ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= pg.PropertyGrid_CollectionChanged; if (objects is INotifyCollectionChanged) ((INotifyCollectionChanged)objects).CollectionChanged += pg.PropertyGrid_CollectionChanged; if (e.OldValue is IEnumerable) foreach (var old in ((IEnumerable)e.OldValue).OfType()) old.PropertyChanged -= pg.PropertyGrid_PropertyChanged; var mis = new List(); foreach (var obj in objects) { if (obj is INotifyPropertyChanged) ((INotifyPropertyChanged)obj).PropertyChanged += pg.PropertyGrid_PropertyChanged; if (obj != null) { pg._modelTreeManager.Load(obj); mis.Add(pg._modelTreeManager.Root); } } pg._onSelectionChanged.Invoke(pg._inspector, new object[] { null }); // clear previous selection pg._onSelectionChanged.Invoke(pg._inspector, new object[] { new Selection(mis) }); } protected void PropertyGrid_PropertyChanged(object sender, PropertyChangedEventArgs e) { OnSelectedObjectChanged(this, new DependencyPropertyChangedEventArgs(SelectedObjectProperty, GetValue(SelectedObjectProperty), GetValue(SelectedObjectProperty))); } protected void PropertyGrid_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { OnSelectedObjectChanged(this, new DependencyPropertyChangedEventArgs(SelectedObjectProperty, GetValue(SelectedObjectProperty), GetValue(SelectedObjectProperty))); } public object SelectedObject { get { return GetValue(SelectedObjectProperty); } set { SetCurrentValue(SelectedObjectProperty, value); } } } }
Aug 6, 2010 at 12:08 AM
Somebody tell me how the freak you format the code.
Aug 11, 2010 at 5:40 PM
Can't help with your problem - but I discovered CodePlex has some of the worst forum software. In short - you have to markup your posts with HTML to get it to format correctly. >=(
Aug 31, 2010 at 3:13 PM
Edited Aug 31, 2010 at 3:13 PM

just put it into


<pre lang="cs">




Sep 1, 2010 at 3:36 AM

Also you can use this one:

Sep 30, 2010 at 4:26 PM

I am having trouble getting this property grid to work with type converters.  It is complaining about missing resources.  Here is the exception i receive if i use a type converter on a property:

NullReferenceException: Object reference not set to an instance of an object.

   at System.Activities.Presentation.Internal.PropertyEditing.PropertyInspectorMergedResources.GetBrush(String key)

   at System.Activities.Presentation.Internal.PropertyEditing.PropertyInspectorMergedResources.get_SelectedForegroundBrush()

To reproduce easily, just create a complex property (object type with its own properties), then set the type converter to ExpandableObjectConverter.

Nov 18, 2010 at 3:43 AM

I ran into the GetBrush problem as well and realized I was missing one part of the initialization:

var pimrType = typeof(WorkflowDesigner).Assembly.GetType("System.Activities.Presentation.Internal.PropertyEditing.PropertyInspectorMergedResources");
var pimrMeth = pimrType.GetMethod("set_PropertyInspectorResources", BindingFlags.Static | BindingFlags.Public);
pimrMeth.Invoke(null, new object[] {_inspector.Resources});

Nov 18, 2010 at 3:45 AM

I should also add the the PropertyGrid does support the standard TypeConverter approach to getting a drop-down. Override GetStandard* in TypeConverter and add a TypeConverterAttribute to reference it. You can also use the AttributeTableBuilder class to put the TypeConverters (or BrowsableAttribute, etc.) onto existing classes.

Nov 19, 2010 at 3:48 PM

Using the TypeConverter attribute with an expandable set of properties appears to not work in this grid. I'm not sure where it's going sour. It works fine for standard values including the "exclusive" list. Any ideas?

Nov 23, 2010 at 3:52 PM

Hey brantheman, we exchanged emails a few times last week (andrew). I have played around with this quite a bit using the TypeConverter and Jamie Olivares' control.

When you use the ExpandableObjectConverter (or your own that returns true on GetPropertiesSupported), it shows a DropDownList that only contains Null.

What's interesting is that if you actually select the Null option the Property gets expanded and you can see the SubProperties as well as the [+] expander button as expected...

(Note: If you're using Olivares' control, you'll have to change the GotFocusHandler since a null exception is thrown when selecting the SubProperties..)

I fear that this comes down to the way MS has implemented either the default Editor (or something related), since if you use one of the other available Editors the GetPropertiesSupported is never hit.

Look forward to any progress... cheers. 

Nov 24, 2010 at 12:06 AM

That is a fascinating discovery on selecting the null value. After I do that and attempt to edit the children (on the Thickness type), the property grid freaks out a bit though. The cells get larger as you type. It's quite exciting.

Nov 25, 2010 at 3:51 PM

I've come to the conclusion that this propertyInspectorView doesn't work properly with "expandable" Struct types. If you add a regular Object-derived property and mark it with the ExpandableObjectConverter, the grid works as expected. It's only when you use a Struct type (like thickness) that it fails. I think it has something to do with how the internal SubPropertyViewEditor class initialises a new object. Maybe a workaround is to create your own class that mimics the functionality of Thickness and add a converter to Thickness. Cheers


Nov 26, 2010 at 6:36 AM

I filed a bug on MSConnect about the ExpandableObjectConverter-with-structs problem. (Good catch on that!)

Mar 22, 2012 at 3:39 PM

I did figure out how to use the fade-out editor that the default grid uses. Here is some sample code:

using System.Activities.Presentation.PropertyEditing;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using Company.Services;
using Company.Units;

namespace Company.Ui.Wpf.Converters
	public class UnitOfMeasureEditor: PropertyValueEditor
		public UnitOfMeasureEditor()
			var type = typeof(PropertyValueEditor).Assembly.GetType("System.Activities.Presentation.Internal.PropertyEditing.Automation.AutomatedChoiceEditor", true, false);
			var itemSourceProperty = (DependencyProperty)type.BaseType.GetField("ItemsSourceProperty", BindingFlags.Public | BindingFlags.Static).GetValue(null);
			var itemValueProperty = (DependencyProperty)type.BaseType.GetField("ValueProperty", BindingFlags.Public | BindingFlags.Static).GetValue(null);

			var lbfac = new FrameworkElementFactory(type);

			var sourceBinding = new Binding();
			sourceBinding.Mode = BindingMode.OneTime;

			var um = ServiceRegistry.Get<UnitsManager>();
			sourceBinding.Source = um.AllUnits;

			lbfac.SetBinding(itemSourceProperty, sourceBinding);

			var valueBinding = new Binding("Value");
			valueBinding.Mode = BindingMode.TwoWay;

			lbfac.SetBinding(itemValueProperty, valueBinding);

			var dt = new DataTemplate();
			dt.VisualTree = lbfac;

			InlineEditorTemplate = dt;

Oct 3, 2013 at 10:39 AM
Did anyone managed to successfully use the wrapped PropertyInspector aka PropertyGrid?

I'm playing around with the Native WPF 4 PropertyGrid. So far I've been able to use the ExpandableObjectConverter for instance types.

But the built-in property search feature only finds properties on the class itself, misses the ExpandableObjectConverter properties.

Any idea how to let the search feature also search trough ExpandableObjectConverter properties?