2008-12-09 16 views
5

ऐसा लगता है कि आपके पास WinForms .NET एप्लिकेशन है, और एक कॉम्बोबॉक्स ("ड्रॉपडाउन" शैली पर सेट है), और कॉम्बोबॉक्स में कई आइटम हैं समान, अजीब चीजें होती हैं। विशेष रूप से, चयनित आइटम की अनुक्रमणिका को के बिना चयनित इंडेक्स चेंज किए गए ईवेंट को फायर कर सकती है।.NET WinForms कॉम्बोबॉक्स, समान आइटम, और चयनित इंडेक्स चेंजेड इवेंट

बेशक, यह बड़े पैमाने पर भ्रम और अजीब, अस्पष्ट त्रुटियों का कारण बनता है, जो मैं हाल ही में अपने बालों को खींच रहा हूं।

यहाँ एक सरल उदाहरण आप को देखने के लिए मैं क्या बात कर रहा हूँ का उपयोग कर सकते है:

  • एक नया नेट WinForms परियोजना (मैं VB.NET उपयोग करें, लेकिन अनुवाद करने के लिए स्वतंत्र लग रहा है - यह काफी सरल हो) ।
  • फॉर्म पर एक कॉम्बोबॉक्स, एक बटन, और टेक्स्टबॉक्स (सेट मल्टीलाइन = ट्रू) ड्रॉप करें।
  • 3 समान आइटम के साथ ComboBox लोड करने के लिए निम्नलिखित कोड का उपयोग और कुछ स्थिति संदेश जब SelectedIndexChanged का ईवेंट आग मुद्रित करने के लिए, और देखने के लिए क्या वर्तमान में चयनित सूचकांक (एक बटन के माध्यम से) है:
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged 
     TextBox1.Text = TextBox1.Text & vbNewLine & "ComboBox SelectedIndexChanged event fired." & vbNewLine & _ 
      "SelectedIndex is: " & ComboBox1.SelectedIndex 
    End Sub 

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
     ComboBox1.Items.Add("John Doe") 
     ComboBox1.Items.Add("John Doe") 
     ComboBox1.Items.Add("John Doe") 

    End Sub 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     TextBox1.Text = TextBox1.Text & vbNewLine & _ 
     "Button clicked." & vbNewLine & _ 
     "SelectedIndex is: " & ComboBox1.SelectedIndex 
    End Sub

प्रोजेक्ट चलाएं और कॉम्बोबॉक्स से एक आइटम चुनें (कहें, मध्य एक)। फिर, कॉम्बोबॉक्स के ड्रॉप-डाउन तीर पर क्लिक करें, लेकिन कुछ भी नहीं चुनें। बटन पर क्लिक करें (डिफ़ॉल्ट रूप से बटन 1) और देखें कि यह क्या कहता है।

जब तक मैं अपने मन खो दिया है, यहाँ आप जो देखते हैं चाहिए:

ComboBox SelectedIndexChanged event fired. 
SelectedIndex is: 1 
Button clicked. 
SelectedIndex is: 0

दूसरे शब्दों में, चुने इंडेक्स परिवर्तित हो गया है, लेकिन SelectedIndexChanged का ईवेंट फायरिंग के बिना!

यह तब होता है जब कॉम्बोबॉक्स में आइटम समान होते हैं। यदि वे अलग हैं, तो ऐसा नहीं होता है। (यह तब भी नहीं होता है जब कॉम्बोबॉक्स की "ड्रॉपडाउन" शैली "ड्रॉपडाउनलिस्ट" पर सेट हो।)

मुझे संदेह है कि यह .NET ढांचे में स्वयं एक बग हो सकता है और कुछ भी मैं ठीक नहीं कर सकता, लेकिन बंद पर मौका है कि किसी और के पास क्या करना है (या मैं क्या गलत कर रहा हूं!) पर कोई विचार है, कृपया इसमें झुक जाओ! मुझे इस व्यवहार को समझाने या इसके चारों ओर काम करने की हानि हो रही है (मुझे उम्मीद है कि चयनित इंडेक्स को तब तक रहने की उम्मीद है जब तक कि आप वास्तव में कुछ और चुनकर इसे बदल दें!)

उत्तर

17

.NET Framework वास्तव में नहीं है कॉम्बो बॉक्स की ड्रॉप डाउन सूची के चयनित इंडेक्स का ट्रैक रखें; यह विंडोज एपीआई द्वारा आंतरिक रूप से संभाला जाता है। इसके परिणामस्वरूप, .NET विंडोज एपीआई पर इसे सूचित करने के लिए निर्भर है जब चयनित इंडेक्स कॉम्बो बॉक्स के विंडो हैंडल को भेजे गए अधिसूचना संदेश के माध्यम से बदलता है, ताकि यह चयनित इंडेक्स चेंजेड ईवेंट को चालू कर सके।

दुर्भाग्यवश, यह पता चला है कि विशेष सूचना संदेश जो .NET के लिए देखता है (CBN_SELCHANGE सटीक होने के लिए) सभी संभावित परिदृश्यों को कवर नहीं करता है जिसमें चयनित अनुक्रमणिका बदल सकती है। विशेष रूप से, CBN_SELCHANGE केवल Windows API द्वारा भेजा जाता है यदि उपयोगकर्ता क्लिक करता है या ड्रॉप डाउन सूची में एक आइटम तीर कुंजियों का उपयोग करता है। हालांकि, ड्रॉपडाउन स्टाइल कॉम्बो बॉक्स में, कॉम्बो बॉक्स खोलने का कार्य कॉम्बो बॉक्स के संपादन हिस्से में टेक्स्ट को देखने के लिए, एक मैच के लिए आइटम्स की सूची के माध्यम से खोजता है, और यदि कोई मिलान स्वचालित रूप से मिलता है, तो स्वचालित रूप से मिलान करने वाली वस्तु का चयन करें (या पहले मिलान करने वाली वस्तु, यदि एकाधिक मिलान करने वाले आइटम हैं)। यह चयनित इंडेक्स को बदल सकता है, लेकिन CBN_SELCHANGE अधिसूचना संदेश नहीं भेजता है, इसलिए .NET इस तथ्य को याद करता है कि यह बदल गया है और चयनित इंडेक्स चेंज किए गए ईवेंट को नहीं चलाता है।

विंडोज यह सब ड्रॉपडाउन स्टाइल कॉम्बो बॉक्स में करता है क्योंकि उपयोगकर्ता को ड्रॉप डाउन सूची में कुछ लेने की ज़रूरत नहीं है; वे जो चाहें टाइप कर सकते हैं। इसलिए प्रत्येक बार जब आप कॉम्बो बॉक्स खोलते हैं तो यह मानता है कि उपयोगकर्ता ने टेक्स्ट बदल दिया होगा और यदि सूची में है तो सूची में क्या सिंक हो सकता है।

अपने मामले में, जब आप दूसरी बार कॉम्बो बॉक्स खोलते हैं, तो यह संपादन भाग में पाठ के लिए पहला मैच फिर से समन्वयित और चयन कर रहा है, जो "जॉन डो" # 0 है, और चयनित को बदल रहा है .NET के बिना 0 से सूचकांक जागरूक है।

तो यह मूल रूप से .NET Framework में एक बग है। दुर्भाग्यवश, कोई सही कामकाज नहीं है - आप विंडोज को फिर से सिंक नहीं करने के लिए प्राप्त नहीं कर सकते हैं, और ऐसी कोई घटना नहीं है जो पुन: सिंक होने के बाद सही हो जाती है जिसमें आप नई चयनित अनुक्रमणिका प्राप्त कर सकते हैं। (ड्रॉपडाउन घटना वास्तव में पुन: सिंक होने से ठीक पहले आग लगती है, इसलिए यह नई अनुक्रमणिका नहीं देखेगी।) सबसे अच्छा आप ड्रॉपडाउन क्लोज़ेड ईवेंट को संभालने के बारे में सोच सकते हैं, मान लीजिए कि उस बिंदु पर सूचकांक बदल सकता है, और तदनुसार कार्य करें ।

+0

उस उत्तर के लिए आपको बहुत बहुत धन्यवाद! वह * अविश्वसनीय रूप से * जानकारीपूर्ण था! (यह जानना भी अच्छा है कि मैं पागल नहीं हूं और इस व्यवहार के लिए एक वैध स्पष्टीकरण है!) – Keithius

+0

मैं मानता हूं कि आग्रह किया गया जवाब इसलिए मैंने जवाब दिया – MikeScott8

1

एरिक का जवाब बहुत गहन था, लेकिन मुझे यह देखकर आश्चर्य हुआ कि यह "समाप्त नहीं हुआ" लेकिन वास्तव में, आपको खुद से पूछना चाहिए कि आप डुप्लिकेट आइटम के साथ कॉम्बो बॉक्स क्यों पॉप्युलेट कर रहे हैं। " .NET फ्रेमवर्क बग में कोई संदेह मौजूद नहीं है क्योंकि जब आप नियंत्रण के रूप में नियंत्रण का उपयोग करते हैं, तो उपयोगकर्ता को सूची से कोई आइटम चुनने की अनुमति देने के लिए, आप इस बग में नहीं भागते हैं।

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

एकमात्र परिदृश्य मैं सोच सकता हूं कि यह कहां समझ सकता है कि जब आपके पास संबंधित वस्तुओं के कई समूहों से युक्त एक बड़ी सूची है, जहां एक या अधिक आइटम तार्किक रूप से एक से अधिक समूह में फिट बैठते हैं तो आप इसे प्रदर्शित करना चाहते हैं दोनों खंड

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

+0

एक पल के लिए विचार करें कि अधिकांश उपयोगकर्ता प्रोग्रामर नहीं हैं, और कोई विचार नहीं है कि एक सूची में 2 आइटम एक ही समस्या हो सकती हैं, और आप समझ जाएंगे कि यह समस्या कैसे उत्पन्न हो सकती है। इसके अलावा: उपयोगकर्ता दुर्घटना से दो बार एक ही चीज़ में प्रवेश कर सकते हैं, लेकिन पहले इसे नोटिस नहीं करते हैं, जिससे इस स्थिति की ओर अग्रसर होता है। – Keithius

1

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

C:\ 
C:\A 
C:\A\B 
C:\A\B\A 

एक पूरी तरह से वैध संरचना:

तो निम्न फ़ोल्डर संरचना की कल्पना। मेरे कार्यान्वयन में मैंने डेटासोर्स प्रॉपर्टी को ऑब्जेक्ट्स के बाध्यकारी सूची में सेट किया। ऑब्जेक्ट का ValueMember पूर्ण फ़ाइल नाम है, और DisplayMember छोटा फ़ाइल नाम है। कॉम्बो बॉक्स प्रदर्शित करना चाहिए:

C:\ 
    A 
     B 
      A 

पूरी तरह से अच्छा यूआई डिज़ाइन। इंडेंटेशन फ़ोल्डर्स के घोंसले का सुझाव देता है।

लेकिन जब मैं कॉम्बो बॉक्स के चयनित वैल्यू को "सी: \ ए \ बी \ ए" पर सेट करता हूं तो गलत आइटम चुना जाता है। जिस आइटम को चुना जाना चाहिए वह सूची में अंतिम (चौथा आइटम) है, लेकिन इसके बजाय दूसरा आइटम (अनुक्रमणिका 1) चुना गया है।और SelectedIndex = 3 को सेट करना इरादे से व्यवहार नहीं करता है। दोबारा, दूसरा आइटम चुना गया है, आखिरी नहीं।

यहां क्या प्रतीत होता है यह है कि जब चयनित वैल्यू या चयनित इंडेक्स सेट करते हैं, तो डिस्प्लेमम्बर संपत्ति का उपयोग करके मूल्य परिवर्तित किया जा रहा है, और नियंत्रण एक मैच के लिए शुरुआत से अंत तक खोज रहा है। यह ValueMember संपत्ति का उपयोग कर खोजना चाहिए। नमूना कोड नीचे है। सराहना की अगर कोई यह पुष्टि कर सकता है कि यह एक बग है, या कुछ ऐसा है जो मैंने गलत किया है।

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace ComboBoxTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
     InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
     if (DesignMode) 
      return; 

     BindingList<CBItem> items = new BindingList<CBItem>(); 
     items.Add(new CBItem("A", @"C:\A")); 
     items.Add(new CBItem("B", @"C:\A\B")); 
     items.Add(new CBItem("A", @"C:\A\B\A")); 

     comboBox.DisplayMember = "DisplayValue"; 
     comboBox.ValueMember = "RealValue"; 
     comboBox.DataSource = items; 

     comboBox.SelectedValue = @"C:\A\B\A"; 
     } 
    } 

    class CBItem 
    { 
     public CBItem(string displayValue, string realValue) 
     { 
     _displayValue = displayValue; 
     _realValue = realValue; 
     } 

     private readonly string _displayValue, _realValue; 

     public string DisplayValue { get { return _displayValue; } } 
     public string RealValue { get { return _realValue; } } 
    } 
} 
0

यदि आप मुफ्त टेक्स्ट दर्ज करते हैं तो समान आइटम होने के बिना एक समान समस्या होती है, जो बिल्कुल सटीक लेकिन पहले वर्णों से मेल नहीं खाती है। यदि उपयोगकर्ता ड्रॉपडाउन नहीं खोलता है तो फिर से सिंक नहीं होता है और चयनित इंडेक्स -1 अपेक्षित है। (आइटम में से किसी एक को चुनना नहीं है जो उपयोगकर्ता करना चाहता है) अब उपयोगकर्ता संवाद बंद कर देता है और इसे फिर से खोल सकता है। आप प्रोग्रामर के रूप में, उपयोगकर्ता द्वारा दर्ज किए गए पाठ के साथ combobox को पुनर्स्थापित करते हैं और पाठ ईवेंट को फायर किए बिना आइटम आंशिक मिलान में स्वतः पूर्ण हो जाता है। यदि उपयोगकर्ता संवाद बंद कर देता है तो टेक्स्ट बिना किसी सूचना के बदल गया है। यह समस्या तब नहीं होती है जब टेक्स्ट किसी आइटम से मेल नहीं खाता है।

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