2009-04-08 7 views
9

SelectedIndexChanged घटना एक कॉम्बो बॉक्स जब से अपने आवेदन में निकाल दिया जाता:उपयोगकर्ता बातचीत द्वारा उठाए गए घटनाओं और अपने खुद के कोड के बीच अंतर करना

  1. उपयोगकर्ता कॉम्बो बॉक्स में एक अलग आइटम चुनता है, या जब:
  2. मेरा खुद का कोड कॉम्बो बॉक्स SelectedItem को को प्रतिबिंबित करने के लिए अद्यतन करता है कॉम्बो बॉक्स अब गुणों को एक अलग ऑब्जेक्ट के लिए प्रदर्शित कर रहा है।

मैं, मामले 1 के लिए SelectedIndexChanged घटना में दिलचस्पी है तो यह है कि मैं वर्तमान ऑब्जेक्ट के गुणों को अपडेट कर सकते हैं। लेकिन 2 मामले में, मैं नहीं चाहता कि घटना आग लग जाए, क्योंकि ऑब्जेक्ट की संपत्तियां नहीं बदली हैं।

एक उदाहरण मदद कर सकता है। आइए मान लें कि मेरे पास एक सूची बॉक्स है जिसमें लोगों की एक सूची है और मेरे पास एक कॉम्बो बॉक्स है जो वर्तमान में चयनित व्यक्ति की सूची में राष्ट्रीयता का प्रतिनिधित्व करता है। केस 1 तब हो सकता है जब फ्रेड वर्तमान में सूची में चुना गया हो, और मैं अपनी राष्ट्रीयता को अंग्रेजी से वेल्श में बदलने के लिए कॉम्बो बॉक्स का उपयोग करता हूं। केस 2 तब हो सकता है जब मैं सूची में बॉब का चयन करता हूं, जो स्कॉटिश है। यहां, मेरी सूची अपडेट इवेंट-हैंडलर कोड देखता है कि बॉब अब चुना गया है, और कॉम्बो बॉक्स अपडेट करता है ताकि स्कॉटिश अब चयनित आइटम हो। इससे कॉम्बो बॉक्स की SelectedIndexChanged घटना को बॉब की राष्ट्रीयता को स्कॉटिश में सेट करने के लिए निकाल दिया जाता है, भले ही यह पहले से ही स्कॉटिश है।

SelectedIndexChanged ईवेंट को आग के बिना मैं अपने कॉम्बो बॉक्स की SelectedItem संपत्ति को कैसे अपडेट कर सकता हूं? इवेंट हैंडलर को अनधिकृत करने का एक तरीका होगा, SelectedItem सेट करें, फिर इवेंट हैंडलर को फिर से पंजीकृत करें, लेकिन यह थकाऊ और त्रुटि प्रवण प्रतीत होता है। इसके लिए अवश्य ही एक बेहतर तरीका होना चाहिए। '

उत्तर

7

मैंने एक कक्षा बनाई जिसे मैंने SuspendLatch कहा। एक बेहतर नाम पर प्रस्ताव का स्वागत करते हैं, लेकिन यह है कि तुम क्या जरूरत है और आप इस तरह यह प्रयोग करेंगे:

void Method() 
{ 
    using (suspendLatch.GetToken()) 
    { 
     // Update selected index etc 
    } 
} 

void listbox1_SelectedIndexChanged(object sender, EventArgs e) 
{ 
    if (suspendLatch.HasOutstandingTokens) 
    { 
     return; 
    } 

    // Do some work 
} 

यह बहुत नहीं है, लेकिन यह काम करता है, और घटनाओं या बूलियन झंडे पंजीकरण रद्द विपरीत, यह नेस्टेड संचालन का समर्थन करता है लेनदेनस्कोप की तरह थोड़ा। आप लेच से टोकन लेते रहते हैं और यह तब होता है जब अंतिम टोकन का निपटारा किया जाता है कि HasOutstandingTokens झूठा रिटर्न देता है। अच्छा और सुरक्षित

public class SuspendLatch 
{ 
    private IDictionary<Guid, SuspendLatchToken> tokens = new Dictionary<Guid, SuspendLatchToken>(); 

    public SuspendLatchToken GetToken() 
    { 
     SuspendLatchToken token = new SuspendLatchToken(this); 
     tokens.Add(token.Key, token); 
     return token; 
    } 

    public bool HasOutstandingTokens 
    { 
     get { return tokens.Count > 0; } 
    } 

    public void CancelToken(SuspendLatchToken token) 
    { 
     tokens.Remove(token.Key); 
    } 

    public class SuspendLatchToken : IDisposable 
    { 
     private bool disposed = false; 
     private Guid key = Guid.NewGuid(); 
     private SuspendLatch parent; 

     internal SuspendLatchToken(SuspendLatch parent) 
     { 
      this.parent = parent; 
     } 

     public Guid Key 
     { 
      get { return this.key; } 
     } 

     public override bool Equals(object obj) 
     { 
      SuspendLatchToken other = obj as SuspendLatchToken; 

      if (other != null) 
      { 
       return Key.Equals(other.Key); 
      } 
      else 
      { 
       return false; 
      } 
     } 

     public override int GetHashCode() 
     { 
      return Key.GetHashCode(); 
     } 

     public override string ToString() 
     { 
      return Key.ToString(); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     protected virtual void Dispose(bool disposing) 
     { 
      if (!disposed) 
      { 
       if (disposing) 
       { 
        // Dispose managed resources. 
        parent.CancelToken(this); 
       } 

       // There are no unmanaged resources to release, but 
       // if we add them, they need to be released here. 
      } 
      disposed = true; 

      // If it is available, make the call to the 
      // base class's Dispose(Boolean) method 
      //base.Dispose(disposing); 
     } 
    } 
} 
+0

मुझे मई दे सकता है। लेकिन क्या यह थोड़ा अधिक नहीं है - "मैं चयनित कॉम्बो बॉक्स की चयनित इटैम संपत्ति को कैसे अपडेट कर सकता हूं बिना चयनित इंडेक्स चेंज इवेंट को आग लगाना?" कृपया मेरे समाधान पर प्रतिक्रिया हो सकती है? –

+0

यह अधिक हो सकता है। झंडे को सेट करना या इवेंटहैंडर को हटाने का एक आसान समाधान है, लेकिन मैंने अपने सस्पेंडलैच को बनाया जब मुझे एहसास हुआ कि मेरे पास कई जगहें हैं जहां मैं चयनित इंडेक्स चेंजेड इवेंट –

+0

"एक बेहतर नाम पर ऑफ़र स्वागत है" - सार्वजनिक वर्ग सस्पेंड टिंगर माजिग? – Juliet

4

मुझे लगता है कि सबसे अच्छा तरीका है एक झंडा चर का उपयोग करने के लिए किया जाएगा:

bool updatingCheckbox = false; 

void updateCheckBox() 
{ 
    updatingCheckBox = true; 

    checkbox.Checked = true; 

    updatingCheckBox = false; 
} 

void checkbox_CheckedChanged(object sender, EventArgs e) 
{ 
    if (!updatingCheckBox) 
     PerformActions() 
} 

[संपादित करें: पोस्ट करना केवल threadsafe नहीं है, हालांकि ...

यहाँ SuspendLatch के लिए कोड है कोड वास्तव में स्पष्ट नहीं है]

इस मामले में, ईवेंट हैंडलर अपने सामान्य संचालन नहीं करेगा जब चेकबॉक्स अपडेटबैकबॉक्स() के माध्यम से बदल जाता है।

+0

यह मेरे SuspendLatch का एक सरल संस्करण है (इस प्रश्न पर कहीं और पोस्ट किया गया है), और जब तक मुझे एहसास हुआ तब तक मैंने जिस विधि का उपयोग किया, मेरे पास कई जगहें थीं जहां मैं चयनित इंडेक्स चेंजेड ईवेंट को निलंबित करना चाहता था। –

+0

वास्तव में, आपके उत्तर को ऊपर उठाया क्योंकि मैं शायद उस विचार का उपयोग करने जा रहा हूं;) – Lennaert

+0

खुशी है कि यह कुछ उपयोग है। थोड़ी देर में हर किसी को कम से कम एक अच्छा विचार रखना अच्छा लगता है :) –

1

मैंने ईवेंट को आग लगा दी। लेकिन, मैंने इंडेक्स को बदलने से पहले एक झंडा लगाया और इसे वापस फ्लिप कर दिया। ईवेंट हैंडलर में, मैं जांचता हूं कि ध्वज सेट है या नहीं, हैंडलर से बाहर निकलें।

1

मुझे लगता है कि आपका ध्यान ऑब्जेक्ट पर होना चाहिए, न कि घटना होने पर।

कहते हैं, उदाहरण के लिए आप घटना है

void combobox_Changed(object sender, EventArgs e) 
{ 
    PerformActions() 
} 

और PerformActions

void PerformActions() 
{ 
    (listBox.SelectedItem as IPerson).Nationality = 
     (comboBox.SelectedItem as INationality) 
} 

के प्रभाव के लिए कुछ किया तो व्यक्ति के अंदर आप

के प्रभाव से कुछ देखने की अपेक्षा करेंगे
class Person: IPerson 
{ 
    INationality Nationality 
    { 
     get { return m_nationality; } 
     set 
     { 
      if (m_nationality <> value) 
      { 
      m_nationality = value; 
      this.IsDirty = true; 
      } 
     } 
    } 
} 

यहां बिंदु यह है कि आप ऑब्जेक्ट को ट्रैक करने का प्रयास करते हैं कि क्या हो रहा है खुद, यूआई नहीं। यह आपको अपनी वस्तुओं पर गंदी ध्वज ट्रैकिंग का ट्रैक रखने देता है, जो बाद में दृढ़ता के लिए उपयोगी हो सकता है।

यह आपके यूआई को भी साफ रखता है और इसे अजीब घटना पंजीकरण कोड प्राप्त करने से रोकता है जो अधिकतर त्रुटि प्रवण होगा।

3

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

आपका ईवेंट हैंडलर कोड इस तरह दिखेगा:

private bool lockEvents; 

protected void MyEventHandler(object sender, EventArgs e) 
{ 
    if (this.lockEvents) 
    { 
     return; 
    } 

    this.lockEvents = true; 
    //Handle your event... 
    this.lockEvents = false; 
} 
0

मैं अंत में एक समाधान भी कई समय निकाले जाने से uncessary घटना से बचने के लिए मिल गया है।

मैं एक काउंटर का उपयोग करता हूं और मैं केवल उन घटनाओं को हुक/अनहूक करता हूं जिन्हें मैं आवश्यकता नहीं होने पर एक बार मास्क करना चाहता हूं, और जब इसकी आवश्यकता होती है।

नीचे दिया गया उदाहरण दिखाता है कि मैं डेटाग्रिड के सेलवैलू चेंजेड ईवेंट को कैसे छुपाता हूं।

EventMask valueChangedEventMask; 

// In the class constructor 
valueChangedEventMask = new EventMask(
    () => { dgv.CellValueChanged += new DataGridViewCellEventHandler(dgv_CellValueChanged); }, 
    () => { dgv.CellValueChanged -= new DataGridViewCellEventHandler(dgv_CellValueChanged); } 
); 

// Use push to hide the event and pop to make it available again. The operation can be nested or be used in the event itself. 
void changeCellOperation() 
{ 
    valueChangedEventMask.Push(); 

    ... 
    cell.Value = myNewCellValue 
    ... 

    valueChangedEventMask.Pop(); 
} 

// The class 
public class EventMask 
{ 
    Action hook; 
    Action unHook; 

    int count = 0; 

    public EventMask(Action hook, Action unHook) 
    { 
     this.hook = hook; 
     this.unHook = unHook; 
    } 

    public void Push() 
    { 
     count++; 
     if (count == 1) 
      unHook(); 
    } 

    public void Pop() 
    { 
     count--; 
     if (count == 0) 
      hook(); 
    } 
}