我有一個具有IList屬性的類MyClassA。我正在使用PropertyGrid控件來顯示MyClassA的所有屬性,我希望通過MyGlassA的PropertyGrid顯示和編輯MyClassB的列表。PropertyGrid如何添加可編輯列表<Class>?
我現在已經顯示在屬性網格中所有其他屬性除了是MyClassB的列表中的屬性。我如何着手將MyClassB列表添加到用戶可以添加/編輯/從列表中刪除項目的屬性網格中?
我還沒有真正能夠找到細講這個作爲然而,儘管我仍然在挖什麼例子。
我有一個具有IList屬性的類MyClassA。我正在使用PropertyGrid控件來顯示MyClassA的所有屬性,我希望通過MyGlassA的PropertyGrid顯示和編輯MyClassB的列表。PropertyGrid如何添加可編輯列表<Class>?
我現在已經顯示在屬性網格中所有其他屬性除了是MyClassB的列表中的屬性。我如何着手將MyClassB列表添加到用戶可以添加/編輯/從列表中刪除項目的屬性網格中?
我還沒有真正能夠找到細講這個作爲然而,儘管我仍然在挖什麼例子。
這是迄今爲止我已經研究出瞭解決辦法,但它仍然在100%不適合於我所期待的。
我發現這個參照修改我的喜好:http://www.codeproject.com/KB/tabs/customizingcollectiondata.aspx
我所做的就是創建一個自CollectionBase繼承和使用的ICustomTypeDescriptor一個新的類。
我這樣做,並實現了基本功能之後,我不得不創建該類的PropertyDescriptor的。
下面是代碼:
public class ZoneCollection : CollectionBase, ICustomTypeDescriptor
{
#region Collection Implementation
/// <summary>
/// Adds an zone object to the collection
/// </summary>
/// <param name="emp"></param>
public void Add(Zone zone)
{
this.List.Add(zone);
}
/// <summary>
/// Removes an zone object from the collection
/// </summary>
/// <param name="emp"></param>
public void Remove(Zone zone)
{
this.List.Remove(zone);
}
/// <summary>
/// Returns an zone object at index position.
/// </summary>
public Zone this[int index]
{
get
{
return (Zone)this.List[index];
}
}
#endregion
// Implementation of interface ICustomTypeDescriptor
#region ICustomTypeDescriptor impl
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 object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
/// <summary>
/// Called to get the properties of this type. Returns properties with certain
/// attributes. this restriction is not implemented here.
/// </summary>
/// <param name="attributes"></param>
/// <returns></returns>
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return GetProperties();
}
/// <summary>
/// Called to get the properties of this type.
/// </summary>
/// <returns></returns>
public PropertyDescriptorCollection GetProperties()
{
// Create a collection object to hold property descriptors
PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);
// Iterate the list of employees
for (int i = 0; i < this.List.Count; i++)
{
// Create a property descriptor for the zone item and add to the property descriptor collection
ZoneCollectionPropertyDescriptor pd = new ZoneCollectionPropertyDescriptor(this, i);
pds.Add(pd);
}
// return the property descriptor collection
return pds;
}
#endregion
}
/// <summary>
/// Summary description for CollectionPropertyDescriptor.
/// </summary>
public class ZoneCollectionPropertyDescriptor : PropertyDescriptor
{
private ZoneCollection collection = null;
private int index = -1;
public ZoneCollectionPropertyDescriptor(ZoneCollection coll, int idx) :
base("#" + idx.ToString(), null)
{
this.collection = coll;
this.index = idx;
}
public override AttributeCollection Attributes
{
get
{
return new AttributeCollection(null);
}
}
public override bool CanResetValue(object component)
{
return true;
}
public override Type ComponentType
{
get
{
return this.collection.GetType();
}
}
public override string DisplayName
{
get
{
Zone zone = this.collection[index];
return zone.ID.ToString();
}
}
public override string Description
{
get
{
Zone zone = this.collection[index];
StringBuilder sb = new StringBuilder();
sb.Append(zone.ID.ToString());
if (zone.Streets.Route != String.Empty || zone.Streets.Crossing != String.Empty)
sb.Append("::");
if (zone.Streets.Route != String.Empty)
sb.Append(zone.Streets.Route);
if (zone.Streets.Crossing != String.Empty)
{
sb.Append(" and ");
sb.Append(zone.Streets.Crossing);
}
return sb.ToString();
}
}
public override object GetValue(object component)
{
return this.collection[index];
}
public override bool IsReadOnly
{
get { return false; }
}
public override string Name
{
get { return "#" + index.ToString(); }
}
public override Type PropertyType
{
get { return this.collection[index].GetType(); }
}
public override void ResetValue(object component)
{
}
public override bool ShouldSerializeValue(object component)
{
return true;
}
public override void SetValue(object component, object value)
{
// this.collection[index] = value;
}
}
路口現在包含ZoneCollection,而不是一個IList,現在我可以編輯/添加/刪除包含在集合內的區域。
現在,如果我能使這個更通用,我會相對高興。我的模型的另一個障礙是我必須使用這個來繼承Collection集合,而不是IList。這完全破壞了我的NHibernate類的映射,現在我不得不嘗試使用上面提到的方法重新映射這個列表。
如果有人想進一步闡述這一點,我會非常感謝一些更深入的瞭解。
我知道這個題目是超過2歲,但也許這可能是對你有意思。
我有一個類似的問題。 開始於:我需要3D空間中的一個點,它應該可以在Property-Grid中配置 爲此,我創建了一個Class Koord。爲了使在PropertyGrid中多變的,我創建了一個新的類別「KoordConverter:TypeConverter的」這是在Vexel(檢查維基百科,找出它是:-))
要創建一個TestBock(一些三維對象使用 )我正在使用一個Vexels列表。 不幸的是,我需要一個TestBlocks列表,在我的程序中,通過Property-Grid可見。
要朵蒙特開始:
public partial class FormMain : Form
{
private BlockProperties _bp = new BlockProperties();
public FormMain()
{
InitializeComponent();
pgProperties.SelectedObject = _bp;
}
[...]
}
的Class BlockProperties包括TestBocks我填了一下,告訴你裏面有什麼的清單。
class BlockProperties
{
public List<TestBocks> Testing { get; set; }
public BlockProperties()
{
Testing = new List<TestBocks>(3);
List<Vexel> t1 = new List<Vexel>(1);
t1.Add(new Vexel(new Koord(1,0,1), 1));
List<Vexel> t2 = new List<Vexel>(2);
t2.Add(new Vexel(new Koord(2, 0, 1), 2));
t2.Add(new Vexel(new Koord(2, 0, 2), 2));
List<Vexel> t3 = new List<Vexel>(3);
t3.Add(new Vexel(new Koord(3, 0, 1), 3));
t3.Add(new Vexel(new Koord(3, 0, 2), 3));
t3.Add(new Vexel(new Koord(3, 0, 3), 3));
TestBocks tb1 = new TestBocks();
tb1.Koords = t1;
TestBocks tb2 = new TestBocks();
tb2.Koords = t2;
TestBocks tb3 = new TestBocks();
tb3.Koords = t3;
Testing.Add(tb1);
Testing.Add(tb2);
Testing.Add(tb3);
[...]
}
[...]
}
接下來是我的TestBlock類,這簡直是直線前進
[Serializable]
public class TestBocks
{
public List<Vexel> Vexels{ get; set; }
public TestBocks()
{
Vexels = new List<Vexel>();
}
}
在Vexels是最神奇的,我需要爲我的計劃: 我甚至把一個ToString()這裏,使在調試過程中很容易。
public class Vexel
{
private Koord _origin;
private double _extent;
public Koord Origin { get { return _origin; } set { _origin = value; } }
public double Extent { get { return _extent; } set { _extent = value; } }
public string ToString()
{
NumberFormatInfo nFormatInfo = new NumberFormatInfo
{
NumberDecimalSeparator = ".",
NumberGroupSeparator = ""
};
return String.Format(nFormatInfo, "Origin;{0};{1};{2};Extent;{3}", _origin.X, _origin.Y, _origin.Z, _extent);
}
public Vexel()
{
_origin = new Koord(0,0,0);
Extent = 0;
}
public Vexel(Koord origin, double extent)
{
//TODO do some checking
_origin = origin;
_extent = extent;
}
到目前爲止,對於PropertyGrid一切正常,但我無法編輯Koords。 該類非常簡單,但在PropertyGrid中不可編輯。 添加TypeConverterClass解決了這個問題(你可以找到Koord的代碼下面的類型轉換器)
[TypeConverter(typeof(KoordConverter))]
[Serializable]
public class Koord
{
private double p_1;
private double p_2;
private double p_3;
public Koord(double x, double y, double z)
{
this.p_1 = x;
this.p_2 = y;
this.p_3 = z;
}
public string ToString()
{
return String.Format("X;{0};Y;{1};Z;{2}", p_1, p_2, p_3);
}
public double X { get { return p_1; } }
public double Y { get { return p_2; } }
public double Z { get { return p_3; } }
}
的類型轉換器是最複雜的代碼編寫。您可以在下面找到它:
public class KoordConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
string text = value as string;
if (text == null)
{
return base.ConvertFrom(context, culture, value);
}
string text2 = text.Trim();
if (text2.Length == 0)
{
return null;
}
if (culture == null)
{
culture = CultureInfo.CurrentCulture;
}
char c = culture.TextInfo.ListSeparator[0];
string[] array = text2.Split(new char[]
{
c
});
int[] array2 = new int[array.Length];
TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
for (int i = 0; i < array2.Length; i++)
{
array2[i] = (int)converter.ConvertFromString(context, culture, array[i]);
}
if (array2.Length == 3)
{
return new Koord(array2[0], array2[1], array2[2]);
}
throw new ArgumentException("TextParseFailedFormat");
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if (value is Koord)
{
if (destinationType == typeof(string))
{
Koord Koord = (Koord)value;
if (culture == null)
{
culture = CultureInfo.CurrentCulture;
}
string separator = culture.TextInfo.ListSeparator + " ";
TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
string[] array = new string[3];
int num = 0;
array[num++] = converter.ConvertToString(context, culture, Koord.X);
array[num++] = converter.ConvertToString(context, culture, Koord.Y);
array[num++] = converter.ConvertToString(context, culture, Koord.Z);
return string.Join(separator, array);
}
if (destinationType == typeof(InstanceDescriptor))
{
Koord Koord2 = (Koord)value;
ConstructorInfo constructor = typeof(Koord).GetConstructor(new Type[]
{
typeof(double),
typeof(double),
typeof(double)
});
if (constructor != null)
{
return new InstanceDescriptor(constructor, new object[]
{
Koord2.X,
Koord2.Y,
Koord2.Z
});
}
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
{
if (propertyValues == null)
{
throw new ArgumentNullException("propertyValues");
}
object obj = propertyValues["X"];
object obj2 = propertyValues["Y"];
object obj3 = propertyValues["Z"];
if (obj == null || obj2 == null || obj3 == null || !(obj is double) || !(obj2 is double) || !(obj3 is double))
{
throw new ArgumentException("PropertyValueInvalidEntry");
}
return new Koord((double)obj, (double)obj2, (double)obj3);
}
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Koord), attributes);
return properties.Sort(new string[]
{
"X",
"Y",
"Z"
});
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
}
基本上所有的這個成立後,它並沒有ploblem修改對象(TestBlocks或每個TestBlock內Vexels) 希望的任何目錄也可以幫助別人,如果他們跨過此主題。
問候
羅賓血
PS:編輯是PropertyGrid中沒有問題,也許你只是沒有得到你的構造吧!? http://i.stack.imgur.com/LD3zf.png
因此,你有一個列表中的列表,你想顯示該列表與某種自定義編輯器爲您的pGrid? –
或多或少。我的Main中有一個MyClassA的列表。 MyClassA的列表綁定到pGrid。每個MyClassA都有一個與它關聯的MyClassB的列表。我想在當前正在顯示的MyClassA的列表中顯示所有MyClassB,並允許用戶編輯與其關聯的每個MyClassB,或者將新的MyClassB添加到包含在MyClassA中的MyClassB的列表中。那有意義嗎? –
這種自定義會要求您爲網格創建自定義編輯器,當給定某種類型的屬性時,它會使用自定義用戶控件顯示它們。如果我理解正確。 –