मैंने एक ICustomTypeDescriptor इंटरफ़ेस और एक शब्दकोश के साथ ठीक यही किया है।
गतिशील गुणों के लिए ICustomTypeDescriptor लागू करना:
मुझे हाल ही में एक ग्रिड दृश्य को रिकॉर्ड ऑब्जेक्ट पर बाँधने की आवश्यकता थी, जिसमें किसी भी संख्या में गुण हो सकते हैं जिन्हें रनटाइम पर जोड़ा और हटाया जा सकता है। यह उपयोगकर्ता को डेटा के एक अतिरिक्त सेट में प्रवेश करने के लिए सेट किए गए परिणाम में एक नया कॉलम जोड़ने की अनुमति देता था।
यह प्रत्येक डेटा 'पंक्ति' को कुंजी के रूप में एक शब्दकोष के रूप में प्राप्त किया जा सकता है जिसमें संपत्ति का नाम और मूल्य एक स्ट्रिंग या एक वर्ग है जो निर्दिष्ट पंक्ति के लिए संपत्ति के मूल्य को संग्रहीत कर सकता है। निश्चित रूप से शब्दकोश की सूची वाली वस्तुएं ग्रिड के लिए बाध्य नहीं हो पाएंगी। यह वह जगह है जहाँ ICustomTypeDescriptor आता है।
डिक्शनरी के लिए एक रैपर क्लास बनाकर और उसे ICustomTypeDescriptor इंटरफ़ेस का पालन करने के लिए किसी ऑब्जेक्ट के लिए रिटर्निंग प्रॉपर्टीज़ के व्यवहार को ओवरराइड किया जा सकता है।
नीचे दिए गए डेटा 'पंक्ति' वर्ग के कार्यान्वयन पर एक नज़र डालें:
public class TestResultRowWrapper : Dictionary<string, TestResultValue>, ICustomTypeDescriptor
{
#region Methods
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return new AttributeCollection(null);
}
string ICustomTypeDescriptor.GetClassName()
{
return null;
}
string ICustomTypeDescriptor.GetComponentName()
{
return null;
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return null;
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return null;
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return null;
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return null;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return new EventDescriptorCollection(null);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return new EventDescriptorCollection(null);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
List<propertydescriptor> properties = new List<propertydescriptor>();
foreach (string key in this.Keys)
{
properties.Add(new TestResultPropertyDescriptor(key));
}
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this.GetType(), attributes);
foreach (PropertyDescriptor oPropertyDescriptor in pdc)
{
properties.Add(oPropertyDescriptor);
}
return new PropertyDescriptorCollection(properties.ToArray());
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(null);
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion Methods
}
नोट: GetProperties विधि में मैं एक बार प्रदर्शन के लिए पढ़े गए प्रॉपर्टीस्क्रिप्ट को कैश कर सकता हूं लेकिन जैसा कि मैं रनटाइम में कॉलम जोड़ रहा हूं और निकाल रहा हूं मैं हमेशा उन्हें फिर से बनाना चाहता हूं।
आप GetProperties विधि में यह भी देखेंगे कि डिक्शनरी प्रविष्टियों के लिए जोड़े गए प्रॉपर्टी डेस्क्रिप्टर, TestResultPropertyDescriptor प्रकार के हैं। यह एक कस्टम प्रॉपर्टी डिस्क्रिप्टर वर्ग है जो यह बताता है कि प्रॉपर्टी को कैसे सेट किया जाता है और कैसे प्राप्त किया जाता है। नीचे दिए गए कार्यान्वयन पर एक नज़र डालें:
public class TestResultPropertyDescriptor : PropertyDescriptor
{
#region Properties
public override Type ComponentType
{
get { return typeof(Dictionary<string, TestResultValue>); }
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type PropertyType
{
get { return typeof(string); }
}
#endregion Properties
#region Constructor
public TestResultPropertyDescriptor(string key)
: base(key, null)
{
}
#endregion Constructor
#region Methods
public override bool CanResetValue(object component)
{
return true;
}
public override object GetValue(object component)
{
return ((Dictionary<string, TestResultValue>)component)[base.Name].Value;
}
public override void ResetValue(object component)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = string.Empty;
}
public override void SetValue(object component, object value)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = value.ToString();
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
#endregion Methods
}
इस वर्ग को देखने के लिए मुख्य गुण GetValue और SetValue हैं। यहाँ आप एक डिक्शनरी के रूप में डाले जा रहे घटक को देख सकते हैं और इसके अंदर मौजूद कुंजी का मूल्य सेट या पुनः प्राप्त किया जा सकता है। इसका महत्त्वपूर्ण यह है कि इस वर्ग में शब्दकोश पंक्ति के आवरण वर्ग में एक ही प्रकार का है अन्यथा कलाकार विफल हो जाएगा। जब डिस्क्रिप्टर बनाया जाता है तो कुंजी (संपत्ति का नाम) पारित हो जाती है और सही मूल्य प्राप्त करने के लिए शब्दकोश को क्वेरी करने के लिए उपयोग किया जाता है।
मेरे ब्लॉग से लिया गया:
गतिशील गुणों के लिए ICustomTypeDescriptor कार्यान्वयन