2012-08-07 6 views
9

मेरे पास कई कस्टम वर्ग हैं जिनका मैं उपयोग कर रहा हूं, मैं समझाऊंगा और उदाहरण पोस्ट करूंगा। यह समझाने के बाद कि वे सभी क्या करते हैं, मैं उन स्थितियों का स्पष्ट रूप से वर्णन करने की कोशिश करूंगा जिनके अंतर्गत मेरी बग हो रही है।कस्टम, जटिल, गतिशील प्रतिबिंब समाधान - सी #

सबसे पहले, मैं कई अलग-अलग प्रकार की वस्तुओं के गुण प्रदर्शित करने के लिए प्रॉपर्टीग्रिड का उपयोग कर रहा हूं। चूंकि प्रॉपर्टीग्रिड का डिफ़ॉल्ट बाध्यकारी उतना ही वर्णनात्मक नहीं था जितना मैं चाहता था, मैंने कुछ कस्टम वर्ग बनाए जिन्हें मैं "प्रदर्शन" वर्ग के रूप में संदर्भित करूंगा। ये डिस्प्ले क्लासेस किसी ऑब्जेक्ट में गुजरकर और फिर गुणों को बनाते हैं जो वास्तविक ऑब्जेक्ट के सार्वजनिक गुणों (और कुछ मामलों के तरीकों) के लिए अच्छी तरह से स्वरूपित स्ट्रिंग्स और विवरण लौटाते हैं।

मैं इसे प्रदर्शित करूंगा कुछ संक्षिप्त उदाहरण कोड के साथ:

यहाँ एक वस्तु मैं अपने PropertyGrid में प्रदर्शित करना चाहते हैं का एक उदाहरण है:

public class Joint 
{ 
    public Joint(...) 
    {...} 

    //properties 
    public string Name { get; set;} 
    public CustomObject CC { get; set;} 
    public List<CustomObject> Custom List { get; set;} 
} 

स्ट्रिंग संपत्ति "नाम" PropertyGrid हालांकि CustomObject और सूची किया था में ठीक प्रदर्शित करता है जिस तरह से बहुत उपयोग लग रहा था प्रदर्शित नहीं करते हैं मेरे लिए दोस्ताना है।

तो मैं इस वर्ग लिख कर एक समाधान बनाने का प्रयास किया:

public class DisplayJoint 
{  

    private Joint _jnt; 

    public DisplayJoint(Joint jnt) 
    { 
     _jnt = jnt; 
    } 

    //properties 
    public string Name { get { return _jnt.Name; } } 

    [TypeConverterAttribute(typeof(ExpandableObjectConverter))] 
    public DisplayCustomObject CC { get { return new DisplayCustomObject(_jnt.CC); } } 

    [TypeConverterAttribute(typeof(ExpandableObjectConverter))] 
    public List<CustomObject> CustomList { get; set;} 
} 

आप उपरोक्त कोड में देख सकते हैं, मैं दोनों मेरे संयुक्त वर्ग और मेरे CustomObject वर्ग के लिए विशेष DisplayClasses बनाया। मेरी प्रोजेक्ट में मेरे पास कई अलग-अलग प्रकार की ऑब्जेक्ट्स हैं जिन्हें एक ही तरह की ओवरलैपिंग डिस्प्ले क्लास गुणों की आवश्यकता होती है।

आप लाइन्स मैं पिछले दो गुण ऊपर जोड़ा देख सकते हैं ऊपर

[TypeConverterAttribute (typeof (ExpandableObjectConverter))]

इस लाइन CustomObject प्रदर्शित मैं कैसे चाहते हैं की मेरी समस्या का हल संपत्ति ग्रिड में (लगभग ... इस पर और बाद में)। हालांकि यह मेरी कस्टम सूची संपत्ति के लिए एक ही तरह से काम नहीं करता है। कस्टम सूची में यह केवल गणना और क्षमता (सूची के वास्तविक गुण) दिखाने के लिए विस्तारित होता है यह समझ में आता है कि यह क्यों है, लेकिन यह वही नहीं था जो मैं चाहता था। मैं सूची में वास्तविक निहित वस्तु देखना चाहता था।

enter image description here

तो यहाँ मेरी जटिल समाधान, this question से शुरू में ले ली है:

मैं दो वर्गों है कि मैं गतिशील गुण के रूप में PropertyGrid बाध्य सूची में वस्तुओं को जोड़ने के लिए उपयोग कर रहा हूँ है। पहला (कस्टम क्लास) downloaded here हो सकता है। इसका उपयोग गतिशील रूप से गुण बनाने के लिए किया जाता है। दूसरी कक्षा (DisplayIEnumerable) का उपयोग मैं पहले से प्राप्त किया गया है और here.

प्रदर्शन IEnumerable क्लास सूची ऑब्जेक्ट्स के माध्यम से loops और प्रत्येक ऑब्जेक्ट में मौजूद जानकारी के साथ खुद को एक संपत्ति जोड़ता है। एक डिस्प्ले क्लास को परिभाषित करने के लिए पारित किया जाता है कि ग्रिड के भीतर उन ऑब्जेक्ट गुणों का प्रतिनिधित्व कैसे किया जाना चाहिए।

इस बिंदु तक सबकुछ बढ़िया काम करता है!के रूप में इस तस्वीर के सबूत (चित्र प्रदान की वर्गों का उपयोग नहीं बनाया गया था, तार, क्लास मैं उपयोग कर रहा हूँ में प्रारूप अलग कर रहे हैं आप प्रासंगिक कोड पर ध्यान केंद्रित करने में मदद करने के कोड स्वरूपण हटाया:

enter image description here

अब जब कि बाद लंबे परिचय, असली सवाल। उपर्युक्त तकनीकों का उपयोग करके मैं एक कक्षा लिखना चाहूंगा जो कस्टमऑब्जेक्ट्स को गतिशील रूप से संभाल सकता है कि मैंने अद्वितीय प्रदर्शन कक्षाएं नहीं लिखी हैं। मैं इस कोड को परीक्षण के लिए आवेदन का उपयोग करने वालों के लिए छोड़ने का इरादा रखता हूं ताकि वे मेरी कंपनी के कस्टम ऑब्जेक्ट्स में से प्रत्येक के लिए एक पूर्ण प्रदर्शन कक्षा के बिना अधिक प्रभावशाली परीक्षण कर सकते हैं। (सैकड़ों हैं) इसके बजाय, संपत्ति को बाध्य करके नीचे कक्षा के साथ ग्रिड, मुझे उम्मीद है कि सभी गुण होंगे वे सूचियां और कस्टम ऑब्जेक्ट्स हैं जिनके पास संबंधित डिस्प्ले क्लास उनके स्थान पर बाध्य होने के लिए हैं।

यहां वह कक्षा है जिसे मैंने पहले ही कोशिश की है और इसके साथ एक बग है। मैं अभी तक अभी तक अपने DisplayIEnumerable वर्ग के साथ सूचियाँ के प्रतिस्थापन को लागू करने की कोशिश की नहीं किया है, मैं बुनियादी कार्यक्षमता पहले काम कर प्राप्त करना चाहता था:

using System; 
using System.ComponentModel; 
using System.Collections.Generic; 
using System.Reflection; 
using System.Collections; 
using System.Windows.Forms; 

    internal class DisplayObject : CustomClass<T> 
    { 
     #region Variables 
     protected T _obj; 
     #endregion 

     #region Constructor 
     public DisplayObject(T obj) 
     { 
     if (obj != null) 
     { 
      try 
      { 
       Type currentType = typeof(T); 
       foreach (PropertyInfo propertyInfo in currentType.GetProperties()) 
       { 
        Attribute[] attributes = new Attribute[1]; 
        if (propertyInfo.GetType() is IEnumerable) 
        attributes[0] = new TypeConverterAttribute(typeof(ExpandableObjectConverter)); 
        else 
        attributes[0] = null; 
        this.Add(new CustomProperty(propertyInfo.Name, propertyInfo, propertyInfo.GetType(), false, true, attributes)); 
       } 
      } 
      catch 
      { 
       MessageBox.Show("Failure!"); 
      } 
     } 
     } 
     #endregion 

     #region Properties 
     [Browsable(false)] 
     public object Item 
     { 
     get { return _obj; } 
     set { _obj = value; } 
     } 
     #endregion 
    } 

जब चलाने के लिए, PropertyGrid प्रकट होता है के रूप में यह कार्य करना चाहिए: Before

हालांकि , एक बार आप तीर का विस्तार करें पर क्लिक करें, कुछ नहीं होता, और तीर गायब हो जाता है: After

क्या है कि ऊपर वर्ग के साथ गलत है मेरी DisplayIEnumerable वर्ग के साथ गलत नहीं है, कि व्यवहार में इस विचरण का कारण बनता है?

मैं इस तरह DisplayObject वर्ग (एक DisplayClass अंदर) का उपयोग कर रहा:

[TypeConverterAttribute(typeof(ExpandableObjectConverter))] 
    public DisplayObject EndJoint { get { if (_member.bcEnd != null) { return new DisplayObject(_member.EndJoint); } else return null; } } 

अग्रिम धन्यवाद! अगर कोई इस सवाल के माध्यम से इसे बनाता है तो मैं बहुत प्रभावित हूं।

+0

क्यों

public class MyItemPropertyDescriptor : PropertyDescriptor { private object _value; public MyItemPropertyDescriptor(string name, object value) : base(name, new[] { new TypeConverterAttribute(typeof(ExpandableObjectConverter)) }) { _value = value; } public override bool IsReadOnly { get { return false; } } public override object GetValue(object component) { return _value; } public override Type PropertyType { get { return _value == null ? typeof(object) : _value.GetType(); } } public override bool ShouldSerializeValue(object component) { return false; } public override Type ComponentType { get { return typeof(object); } } public override bool CanResetValue(object component) { return false; } public override void ResetValue(object component) { } public override void SetValue(object component, object value) { } } 

अब, यहाँ कुछ नमूना कोड है क्या आप एक मानक संग्रह UITypeEditor (दो स्तंभों के साथ मानक रूप) का उपयोग नहीं करते हैं? –

+0

क्योंकि मैं गुणों के भीतर निहित गुणों में इस विस्तार योग्य विशेषता को दोबारा जोड़ने में सक्षम नहीं हूं। मैं चाहता हूं कि उपयोगकर्ता अलग-अलग ऑब्जेक्ट्स – jth41

+0

के बीच संबंधों को पूरी तरह से देखना चाहते हैं, जहां तक ​​ड्रिल करने में सक्षम होना चाहिए मानक संग्रह फ़ॉर्म में एक संपत्ति ग्रिड शामिल है, इसलिए यह भी रिकर्सिव है। –

उत्तर

5

आपको संपत्ति ग्रिड का उपयोग करने के लिए विशेष कक्षाएं बनाने की आवश्यकता नहीं है। उचित गुणों के साथ गुणों को सजाने के लिए। यहाँ एक उदाहरण है:

दो कस्टम कक्षाएं:

public class MyObjType1 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public override string ToString() 
    { 
     return Name; 
    } 
} 

public class MyObjType2 
{ 
    public string Reference { get; set; } 

    public override string ToString() 
    { 
     return Reference; 
    } 
} 

नोट ToString ओवरराइड है, कि क्या संपत्ति ग्रिड डिफ़ॉल्ट रूप से उपयोग करता है, तो कोई TypeConverter एक दिया प्रकार के लिए परिभाषित किया जाता है।

एक "धारक" वर्ग कस्टम वस्तुओं का संग्रह है:

public class MyHolder 
{ 
    public MyHolder() 
    { 
     Objects = new List<object>(); 
    } 

    public string Name { get; set; } 

    [TypeConverter(typeof(MyCollectionConverter))] 
    public List<object> Objects { get; private set; } 
} 

नोट कस्टम TypeConverterObjects संपत्ति के लिए सीधे आवेदन किया।

public class MyCollectionConverter : ExpandableObjectConverter 
{ 
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
    { 
     IEnumerable enumerable = value as IEnumerable; 
     if (enumerable == null) 
      return base.GetProperties(context, value, attributes); 

     int i = 0; 
     List<PropertyDescriptor> list = new List<PropertyDescriptor>(); 
     foreach (object obj in enumerable) 
     { 
      MyItemPropertyDescriptor index = new MyItemPropertyDescriptor(i.ToString(), obj); 
      list.Add(index); 
      i++; 
     } 
     return new PropertyDescriptorCollection(list.ToArray()); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType != typeof(string)) 
      return base.ConvertTo(context, culture, value, destinationType); 

     IEnumerable enumerable = value as IEnumerable; 
     if (enumerable == null) 
      return base.ConvertTo(context, culture, value, destinationType); 

     StringBuilder sb = new StringBuilder(); 
     foreach (object obj in enumerable) 
     { 
      if (sb.Length > 0) 
      { 
       sb.Append(','); 
      } 
      sb.AppendFormat("{0}", obj); 
     } 
     return sb.ToString(); 
    } 
} 

नोट हम ConvertTo ओवरराइड और यह एक विशेष स्ट्रिंग उस सूची में वस्तुओं की एक अल्पविराम से अलग सूची प्रदर्शित करता है दे: यहाँ स्रोत है। GetProperties भी ओवर्रिडन है और एक विशेष PropertyDescriptor का उपयोग करता है; ताकि वे भी विस्तार किया जा सकता यह उप वस्तुओं के लिए एक ExpandableObjectConverter विशेषता जोड़ता है:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     MyHolder holder = new MyHolder(); 
     for (int i = 0; i < 3; i++) 
     { 
      holder.Objects.Add(new MyObjType1 { Id = i, Name = i + "Name" }); 
     } 
     for (int i = 0; i < 3; i++) 
     { 
      holder.Objects.Add(new MyObjType2 { Reference = "Ref" + i }); 
     } 
     propertyGrid1.SelectedObject = holder; 
    } 
} 

और परिणाम:

enter image description here

+0

कुछ दिन पहले आपकी टिप्पणी का उत्तर देने में असमर्थ होने के लिए खेद है, मैं यात्रा कर रहा हूं और इसे वापस एसओ में वापस कर दिया है, यह उत्तर सिर्फ वही है जो मुझे चाहिए धन्यवाद। – jth41

+0

इसके अलावा, अगर आपको मुझसे कोई फर्क नहीं पड़ता .. आपने अभी मेरे कुछ सवालों का जवाब दिया है और मैं वास्तव में मदद की सराहना करता हूं, लेकिन मैं आपकी प्रोफ़ाइल पर ध्यान नहीं दे सका लेकिन आपके द्वारा दिए गए सभी सवालों के साथ, आप एक भी नहीं पूछा है ?? – jth41

+0

@ जॉन - नहीं, मुझे आमतौर पर अकेले मेरे प्रश्नों के उत्तर मिलते हैं (SO बीटीडब्ल्यू पर कई) :-) –

1

टाइपकॉन्टरर्स के साथ स्वयं काम करने के बाद, मैं पुष्टि कर सकता हूं कि वे नीचे के हिस्सों में एक बड़ा दर्द हैं। आप क्या वास्तव में गलत है, केवल अजीब उत्पादन हो रहा है के बारे में नाडा जानकारी प्राप्त ...

Idk अगर यह मदद करता है, लेकिन शायद यह एक समस्या यह है कि आप कुछ भी है कि है नहीं एक IEnumerable के लिए एक खाली (शून्य) सरणी जोड़ने है ? अगर (...) के दायरे में एड निर्देश को स्थानांतरित करने का प्रयास करें। मुझे नहीं लगता कि इसमें कोई नुकसान है।

इसके अलावा, क्या आप निश्चित हैं कि (एंडजॉइंट के साथ अंतिम उदाहरण में) गेटर एक शून्य सूचक वापस नहीं करता है? रिक्त प्रविष्टियां मेरे अनुभवों से गुजरने वाले नल पॉइंटर्स की तरह गंध करती हैं।

+0

का समर्थन करते हैं, डीफ़ समझते हैं कि खराब फीडबैक और टाइप कन्वर्टर्स के बारे में आपका क्या मतलब है, मुझे यकीन नहीं है कि मैं समझता हूं कि अगर आप को जोड़ के दायरे में जोड़ने के बारे में क्या मतलब है। क्या आप दृश्य चित्रण के लिए कुछ कोड प्रदान कर सकते हैं? धन्यवाद – jth41

संबंधित मुद्दे