Posted 16 years ago
by Aleksander Brzozowski
Version: 4.5.0486
Platform: .NET 3.5
Environment: Windows Vista (32-bit)
Hi
For example, we have list with objects (different classes) with different properties.
To show properties in PropertyGrid we use PropertyEditors. Every time SelectedObject changed we must clear propertyEditors and add new for edited object.It causes that GetProperties(Attribute[] attributes) function from ICustomTypeDescriptor is called many times in different threads. If our function GetProperties returns TypeDescriptor.GetProperties(this, attributes, true) everything is ok, but when we override GetProperties and do something in this function(what get some time) property grid doesnt refresh correct selected object.
In addition we can get error "called thread cannot access to other thread", as I wrote in previous topic. Bellow is sample.I can send You all sample if You want.
Best regards
Alex
For example, we have list with objects (different classes) with different properties.
To show properties in PropertyGrid we use PropertyEditors. Every time SelectedObject changed we must clear propertyEditors and add new for edited object.It causes that GetProperties(Attribute[] attributes) function from ICustomTypeDescriptor is called many times in different threads. If our function GetProperties returns TypeDescriptor.GetProperties(this, attributes, true) everything is ok, but when we override GetProperties and do something in this function(what get some time) property grid doesnt refresh correct selected object.
In addition we can get error "called thread cannot access to other thread", as I wrote in previous topic. Bellow is sample.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;
using ActiproSoftware.Windows.Controls.PropertyGrid;
using ActiproSoftware.Windows.Controls.PropertyGrid.Editors;
using ActiproSoftware.Windows.Controls.PropertyGrid.Primitives;
namespace PropertyGridBugApp
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public static ListBox LogBox;
public Window1()
{
InitializeComponent();
DataTemplate template = new DataTemplate();
template.VisualTree = new FrameworkElementFactory(typeof(SomeClassTemplate), "fef");
lbList.ItemTemplate = template;
List<object> list = new List<object>();
for (int i = 0; i < 5; i++)
{
SomeClass someObject = new SomeClass();
someObject.PropertyA = i;
someObject.PropertyB = (decimal)i / 2;
someObject.PropertyC = "Object " + i.ToString();
list.Add(someObject);
}
for (int i = 0; i < 5; i++)
{
OtherClass someObject = new OtherClass();
someObject.PropertyA = DateTime.Now;
someObject.PropertyC = "Other Object " + i.ToString();
list.Add(someObject);
}
for (int i = 5; i < 10; i++)
{
SomeClass someObject = new SomeClass();
someObject.PropertyA = i;
someObject.PropertyB = (decimal)i / 2;
someObject.PropertyC = "Object " + i.ToString();
list.Add(someObject);
}
lbList.ItemsSource = list;
lbList.SelectionChanged += new SelectionChangedEventHandler(lbList_SelectionChanged);
LogBox = log;
LogBox.Items.Add("Main Thread Id = " + Thread.CurrentThread.ManagedThreadId.ToString());
}
void ClearAndLoadPropertyEditors(object obj)
{
pg.PropertyEditors.Clear();
pg.CategoryEditors.Clear();
if (obj is SomeClass)
{
PropertyEditor pe1 = new PropertyEditor();
pe1.PropertyName = "PropertyA";
pe1.PropertyType = typeof(int);
pe1.ValueTemplate = new DataTemplate();
pe1.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property1Template), "p1");
PropertyEditor pe2 = new PropertyEditor();
pe2.PropertyName = "PropertyB";
pe2.PropertyType = typeof(decimal);
pe2.ValueTemplate = new DataTemplate();
pe2.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property2Template), "p2");
PropertyEditor pe3 = new PropertyEditor();
pe3.PropertyName = "PropertyC";
pe3.PropertyType = typeof(string);
pe3.ValueTemplate = new DataTemplate();
pe3.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property3Template), "p3");
pg.PropertyEditors.Add(pe1);
pg.PropertyEditors.Add(pe2);
pg.PropertyEditors.Add(pe3);
}
else
{
PropertyEditor pe3 = new PropertyEditor();
pe3.PropertyName = "PropertyC";
pe3.PropertyType = typeof(string);
pe3.ValueTemplate = new DataTemplate();
pe3.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property3Template), "p3");
pg.PropertyEditors.Add(pe3);
}
}
bool PropertyContained(string PropertyName)
{
for (int i = 0; i < pg.PropertyEditors.Count; i++)
{
if (pg.PropertyEditors[i].PropertyName.Equals(PropertyName)) return true;
}
return false;
}
void LoadPropertyEditorsIfNotContained(object obj)
{
//pg.PropertyEditors.Clear();
//pg.CategoryEditors.Clear();
if (obj is SomeClass)
{
PropertyEditor pe1 = new PropertyEditor();
pe1.PropertyName = "PropertyA";
pe1.PropertyType = typeof(int);
pe1.ValueTemplate = new DataTemplate();
pe1.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property1Template), "p1");
PropertyEditor pe2 = new PropertyEditor();
pe2.PropertyName = "PropertyB";
pe2.PropertyType = typeof(decimal);
pe2.ValueTemplate = new DataTemplate();
pe2.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property2Template), "p2");
PropertyEditor pe3 = new PropertyEditor();
pe3.PropertyName = "PropertyC";
pe3.PropertyType = typeof(string);
pe3.ValueTemplate = new DataTemplate();
pe3.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property3Template), "p3");
if (!PropertyContained(pe1.PropertyName)) pg.PropertyEditors.Add(pe1);
if (!PropertyContained(pe2.PropertyName)) pg.PropertyEditors.Add(pe2);
if (!PropertyContained(pe3.PropertyName)) pg.PropertyEditors.Add(pe3);
}
else
{
PropertyEditor pe3 = new PropertyEditor();
pe3.PropertyName = "PropertyC";
pe3.PropertyType = typeof(string);
pe3.ValueTemplate = new DataTemplate();
pe3.ValueTemplate.VisualTree = new FrameworkElementFactory(typeof(Property3Template), "p3");
if (!PropertyContained(pe3.PropertyName)) pg.PropertyEditors.Add(pe3);
}
}
void lbList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LoadPropertyEditorsIfNotContained(e.AddedItems[0]);
//ClearAndLoadPropertyEditors(e.AddedItems[0]); //doesnt work
pg.SelectedObject = lbList.SelectedValue;
}
}
class SomeClass : ICustomTypeDescriptor
{
private int a;
private decimal b;
private string s;
public int PropertyA
{
set { this.a = value; }
get { return this.a; }
}
public decimal PropertyB
{
set { this.b = value; }
get { return this.b; }
}
public string PropertyC
{
set { this.s = value; }
get { return this.s; }
}
#region ICustomTypeDescriptor members
public String GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public String GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
void ShowLog(string log)
{
Window1.LogBox.Items.Insert(0, log);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
LogHandler lh = new LogHandler(ShowLog);
Window1.LogBox.Dispatcher.BeginInvoke(lh, "Get Properties in Thread id = " + Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(80); // in thisplace could be function which do something (for example prepare properties)
return TypeDescriptor.GetProperties(this, attributes, true);
}
public PropertyDescriptorCollection GetProperties()
{
return TypeDescriptor.GetProperties(this, true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion
}
class OtherClass : ICustomTypeDescriptor
{
private DateTime dt;
private string s;
public DateTime PropertyA
{
set { this.dt = value; }
get { return this.dt; }
}
public string PropertyC
{
set { this.s = value; }
get { return this.s; }
}
#region ICustomTypeDescriptor members
public String GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public String GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
LogHandler lh = new LogHandler(ShowLog);
Window1.LogBox.Dispatcher.BeginInvoke(lh, "Get Properties in Thread id = " + Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(50); // in thisplace could be function which do something (for example prepare properties)
return TypeDescriptor.GetProperties(this, attributes, true);
}
public PropertyDescriptorCollection GetProperties()
{
return TypeDescriptor.GetProperties(this, true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
void ShowLog(string log)
{
Window1.LogBox.Items.Insert(0, log);
}
#endregion
}
public delegate void LogHandler(string log);
}
Best regards
Alex