आह्वान (प्रतिनिधि)


93

क्या कोई इस लिंक पर लिखे इस कथन की व्याख्या कर सकता है

Invoke(Delegate):

नियंत्रण के अंतर्निहित विंडो हैंडल के मालिक थ्रेड पर निर्दिष्ट प्रतिनिधि को निष्पादित करता है

क्या कोई समझा सकता है कि इसका क्या मतलब है (विशेष रूप से बोल्ड) मैं इसे स्पष्ट रूप से प्राप्त करने में सक्षम नहीं हूं


4
इस प्रश्न का उत्तर Control.InvokeRequired प्रॉपर्टी से बंधा हुआ है - देखें msdn.microsoft.com/en-us/library/…
डैश

जवाबों:


131

इस सवाल का जवाब है कि C # नियंत्रण कैसे काम करता है

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

नियंत्रण से। InvokeRequired

प्रभावी रूप से, इनवोक क्या करता है यह सुनिश्चित करता है कि जिस कोड को आप कॉल कर रहे हैं वह उस थ्रेड पर होता है जो नियंत्रण "प्रभावी रूप से क्रॉस थ्रेडेड अपवादों को रोकने" पर रहता है।

ऐतिहासिक दृष्टिकोण से, .Net 1.1 में, यह वास्तव में अनुमति दी गई थी। इसका मतलब यह है कि आप किसी भी पृष्ठभूमि के धागे से "जीयूआई" धागे पर कोड की कोशिश कर सकते हैं और इसे लागू कर सकते हैं। कभी-कभी यह आपके ऐप को बाहर निकलने का कारण बनता है क्योंकि आप जीयूआई थ्रेड को प्रभावी ढंग से बाधित कर रहे थे जबकि यह कुछ और कर रहा था। यह क्रॉस थ्रेडेड अपवाद है - एक टेक्स्टबॉक्स को अपडेट करने की कोशिश करने की कल्पना करें जबकि जीयूआई कुछ और पेंटिंग कर रहा है।

  • कौन सी कार्यवाही प्राथमिकता पर है?
  • क्या एक ही बार में दोनों का होना संभव है?
  • GUI को चलाने के लिए अन्य सभी कमांड का क्या होता है?

प्रभावी रूप से, आप एक कतार में व्यवधान डाल रहे हैं, जिसके बहुत सारे अप्रत्याशित परिणाम हो सकते हैं। आह्वान प्रभावी रूप से "विनम्र" होने का तरीका है कि आप उस कतार में क्या करना चाहते हैं, और यह नियम .net 2.0 से आगे फेंक दिया गया । InvalidOperationException के माध्यम से लागू किया गया ।

यह समझने के लिए कि वास्तव में पर्दे के पीछे क्या चल रहा है, और "जीयूआई थ्रेड" का क्या मतलब है, यह समझना उपयोगी है कि संदेश पंप या संदेश लूप क्या है।

यह वास्तव में पहले से ही प्रश्न " व्हाट ए मैसेज पंप " में उत्तर दिया गया है और वास्तविक तंत्र को समझने के लिए पढ़ने की सिफारिश की जाती है जिसे आप नियंत्रण के साथ बातचीत करते समय बांध रहे हैं।

आपके द्वारा उपयोगी अन्य पढ़ने में शामिल हो सकते हैं:

शुरुआत के साथ क्या हो रहा है

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

और, प्रतिनिधि नमूने के साथ अधिक कोड भारी अवलोकन के लिए:

अमान्य क्रॉस-थ्रेड ऑपरेशन

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

एक बार जब आप InvokeRequired के लिए सराहना करते हैं, तो आप इन कॉल को रैप करने के लिए एक एक्सटेंशन विधि का उपयोग करने पर विचार कर सकते हैं। यह स्टैक ओवरफ्लो प्रश्न में कवर अप को कवर किया गया है । इनवॉइस आवश्यक के साथ कोड को साफ किया गया है

ऐतिहासिक रूप से जो कुछ हुआ, वह आगे भी लिखा जा सकता है।


68

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

उदाहरण के लिए, यदि आप किसी श्रमिक थ्रेड से किसी लेबल का पाठ बदलना चाहते हैं, तो आप कुछ इस तरह से कर सकते हैं:

theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));

क्या आप समझा सकते हैं कि कोई ऐसा क्यों करेगा? वर्तमान धागे में निश्चित रूप से this.Invoke(() => this.Enabled = true);जो कुछ भी thisसंदर्भित है, वह सही है?
काइल डेलाने

1
@KyleDelaney, एक थ्रेड में "ऑब्जेक्ट" नहीं है, और वर्तमान थ्रेड आवश्यक रूप से वह धागा नहीं है जिसने ऑब्जेक्ट बनाया है।
थॉमस लेवेस्क

24

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

नीचे नमूना थ्रेड 1 में एक अपवाद फेंकता है क्योंकि SetText1 textBox1.Text को किसी अन्य थ्रेड से संशोधित करने का प्रयास कर रहा है। लेकिन थ्रेड 2 में, SetText2 में एक्शन को उस थ्रेड में निष्पादित किया जाता है जिसमें टेक्स्टबॉक्स बनाया गया था

private void btn_Click(object sender, EvenetArgs e)
{
    var thread1 = new Thread(SetText1);
    var thread2 = new Thread(SetText2);
    thread1.Start();
    thread2.Start();
}

private void SetText1() 
{
    textBox1.Text = "Test";
}

private void SetText2() 
{
    textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}

मुझे वास्तव में यह दृष्टिकोण पसंद है, यह प्रकृति के प्रतिनिधियों को छुपाता है, लेकिन यह वैसे भी अच्छा शॉर्टकट है।
shytikov

7
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });

System.Action लोगों का उपयोग अन्य प्रतिक्रियाओं पर सुझाव देता है केवल पुराने संस्करणों के लिए फ्रेमवर्क 3.5+ पर काम करता है, यह पूरी तरह से काम करता है
Suicide Platypus

2

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

पैटर्न है:

void OnEvent(object sender, EventArgs e)
{
   if (this.InvokeRequired)
   {
       this.Invoke(() => this.OnEvent(sender, e);
       return;
   }

   // do stuff (now you know you are on the main thread)
}

2

this.Invoke(delegate)सुनिश्चित करें कि आप प्रतिनिधि this.Invoke()को मुख्य धागे / निर्मित धागे पर तर्क दे रहे हैं ।

मैं कह सकता हूं कि एक मुख्य नियम आपके सूत्र नियंत्रणों को मुख्य धागे को छोड़कर एक्सेस नहीं करता है।

हो सकता है कि निम्नलिखित लाइनें इनवोक () का उपयोग करने के लिए समझ में आए

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox1.InvokeRequired)
        {   
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

ऐसी स्थितियाँ हैं जब आप थ्रेडपूल थ्रेड बनाते हैं (यानी वर्कर थ्रेड) यह मुख्य थ्रेड पर चलेगा। यह एक नया धागा नहीं बनाएगा coz मुख्य धागा आगे के निर्देशों के प्रसंस्करण के लिए उपलब्ध है। इसलिए पहले जाँच करें कि क्या चालू थ्रेड मुख्य थ्रेड है, this.InvokeRequiredयदि यह सही है कि रिटर्न सही कोड वर्कर थ्रेड पर चल रहा है, तो इसे कॉल करें। इंवोक (डी, न्यू ऑब्जेक्ट [] {टेक्स्ट});

UI नियंत्रण को सीधे अपडेट करें (यहां आपको गारंटी दी गई है कि आप मुख्य थ्रेड पर कोड चला रहे हैं।)


1

इसका मतलब है कि प्रतिनिधि यूआई थ्रेड पर चलेगा, भले ही आप पृष्ठभूमि कार्यकर्ता या थ्रेड-पूल थ्रेड से उस पद्धति को कॉल करें। UI तत्वों में थ्रेड एफिनिटी है - वे केवल एक थ्रेड पर सीधे बात करना पसंद करते हैं: UI थ्रेड। UI थ्रेड को नियंत्रण आवृत्ति बनाने वाले थ्रेड के रूप में परिभाषित किया गया है, और इसलिए इसे विंडो हैंडल से संबद्ध किया गया है। लेकिन यह सब एक कार्यान्वयन विवरण है।

मुख्य बिंदु यह है: आप इस विधि को एक कार्यकर्ता थ्रेड से कॉल करेंगे ताकि आप UI तक पहुंच सकें (लेबल में मान को बदलने के लिए, आदि) - चूंकि आपको यूआई थ्रेड के अलावा किसी अन्य थ्रेड से ऐसा करने की अनुमति नहीं है


0

प्रतिनिधि अनिवार्य रूप से इनलाइन Actionया हैं Func<T>। आप एक विधि के दायरे के बाहर एक प्रतिनिधि की घोषणा कर सकते हैं जिसे आप चला रहे हैं या एक lambdaअभिव्यक्ति ( =>) का उपयोग कर रहे हैं ; क्योंकि आप एक विधि के भीतर प्रतिनिधि को चलाते हैं, आप इसे उस थ्रेड पर चलाते हैं जो वर्तमान विंडो / एप्लिकेशन के लिए चलाया जा रहा है जो कि बोल्ड में थोड़ा सा है।

लंबोदर उदाहरण

int AddFiveToNumber(int number)
{
  var d = (int i => i + 5);
  d.Invoke(number);
}

0

इसका मतलब है कि आपके द्वारा पास किया गया प्रतिनिधि उस थ्रेड पर निष्पादित होता है जिसने कंट्रोल ऑब्जेक्ट (जो यूआई थ्रेड है) बनाया है।

आपको इस विधि को कॉल करने की आवश्यकता है जब आपका एप्लिकेशन बहु-थ्रेडेड है और आप UI थ्रेड के अलावा किसी थ्रेड से कुछ UI ऑपरेशन करना चाहते हैं, क्योंकि यदि आप किसी नियंत्रण को किसी भिन्न थ्रेड से नियंत्रण पर कॉल करने का प्रयास करते हैं, तो आपको एक System.InvalidOperationException।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.