क्रॉस-थ्रेड ऑपरेशन मान्य नहीं: जिस थ्रेड पर यह बनाया गया था, उसके अलावा किसी थ्रेड से एक्सेस कंट्रोल


584

मेरा एक परिदृश्य है। (विंडोज फॉर्म, C #, .NET)

  1. एक मुख्य रूप है जो कुछ उपयोगकर्ता नियंत्रण को होस्ट करता है।
  2. उपयोगकर्ता नियंत्रण कुछ भारी डेटा ऑपरेशन करता है, जैसे कि अगर मैं सीधे UserControl_Loadविधि को कॉल करता हूं तो UI लोड विधि के निष्पादन के लिए अवधि के लिए गैर-जिम्मेदार हो जाता है।
  3. इसे दूर करने के लिए मैं विभिन्न थ्रेड पर डेटा लोड करता हूं (मौजूदा कोड को जितना हो सके बदलने की कोशिश कर रहा हूं)
  4. मैंने एक बैकग्राउंड वर्कर थ्रेड का उपयोग किया था जो डेटा लोड कर रहा होगा और जब किया जाएगा तो उस एप्लिकेशन को सूचित करेगा कि इसने अपना काम किया है।
  5. अब असली समस्या आई। सभी यूआई (मुख्य रूप और इसके बच्चे usercontrols) को प्राथमिक मुख्य धागे पर बनाया गया था। Usercontrol के LOAD विधि में मैं userControl पर कुछ नियंत्रण (जैसे टेक्स्टबॉक्स) के मूल्यों के आधार पर डेटा प्राप्त कर रहा हूं।

स्यूडोकोड इस तरह दिखेगा:

कोड १

UserContrl1_LoadDataMethod()
{
    if (textbox1.text == "MyName") // This gives exception
    {
        //Load data corresponding to "MyName".
        //Populate a globale variable List<string> which will be binded to grid at some later stage.
    }
}

यह दिया गया अपवाद था

क्रॉस-थ्रेड ऑपरेशन मान्य नहीं: जिस थ्रेड पर यह बनाया गया था, उसके अलावा किसी थ्रेड से एक्सेस कंट्रोल।

इसके बारे में अधिक जानने के लिए मैंने कुछ काम किया और निम्नलिखित कोड का उपयोग करने जैसा एक सुझाव आया

CODE 2

UserContrl1_LoadDataMethod()
{
    if (InvokeRequired) // Line #1
    {
        this.Invoke(new MethodInvoker(UserContrl1_LoadDataMethod));
        return;
    }

    if (textbox1.text == "MyName") // Now it wont give an exception
    {
    //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be binded to grid at some later stage
    }
}

लेकिन मुझे लगता है ... मैं एक वर्ग में वापस आ रहा हूँ लगता है। एप्लिकेशन फिर से गैर-जिम्मेदार हो जाता है। ऐसा लगता है अगर हालत # 1 # लाइन के निष्पादन के कारण होता है। लोडिंग कार्य फिर से पैरेंट थ्रेड द्वारा किया जाता है, न कि तीसरा जिसे मैंने देखा।

मुझे नहीं पता कि मुझे यह सही लगता है या गलत। मैं थ्रेडिंग में नया हूं।

मैं इसे कैसे हल करूं और यह भी बताएं कि यदि ब्लॉक # 1 लाइन के निष्पादन का प्रभाव क्या है?

स्थिति यह है : मैं एक नियंत्रण के मूल्य के आधार पर एक वैश्विक चर में डेटा लोड करना चाहता हूं। मैं बच्चे के धागे से नियंत्रण के मूल्य को बदलना नहीं चाहता। मैं इसे एक बच्चे के धागे से कभी नहीं करने जा रहा हूं।

इसलिए केवल मान को एक्सेस करना ताकि डेटाबेस से संबंधित डेटा प्राप्त किया जा सके।


इस त्रुटि के अपने विशेष उदाहरण के लिए, मुझे कोड के डेटा-गहन भागों को संभालने के लिए प्रपत्र पर एक BackgroundWorker का उपयोग करने के लिए वर्कअराउंड मिला। (यानी सभी समस्या कोड को बैकग्राउंडवर्कर 1_डॉवर्क्स () मेथड में डालें और बैकग्राउंडवर्क्स 1 के माध्यम से कॉल करें। RunWorkerAsync ()) ... इन दो स्रोतों ने मुझे सही दिशा में बताया: stackoverflow- questions/4806742/… youtube.com/ घड़ी? v = MLrrbG6V1zM
Giollia

जवाबों:


433

प्रति के के अपडेट के अनुसार टिप्पणी (हटाए जाने के बाद से):

मुझे लगता है कि मैंने प्रश्न को ठीक से प्रस्तुत नहीं किया है।

स्थिति यह है: मैं एक नियंत्रण के मूल्य के आधार पर एक वैश्विक चर में डेटा लोड करना चाहता हूं। मैं बच्चे के धागे से नियंत्रण के मूल्य को बदलना नहीं चाहता। मैं इसे एक बच्चे के धागे से कभी नहीं करने जा रहा हूं।

इसलिए केवल मान को एक्सेस करना ताकि डेटाबेस से संबंधित डेटा प्राप्त किया जा सके।

फिर आप जो समाधान चाहते हैं, वह इस तरह दिखना चाहिए:

UserContrl1_LOadDataMethod()
{
    string name = "";
    if(textbox1.InvokeRequired)
    {
        textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
    }
    if(name == "MyName")
    {
        // do whatever
    }
}

नियंत्रण के थ्रेड पर वापस जाने का प्रयास करने से पहले अलग थ्रेड में अपनी गंभीर प्रसंस्करण करें । उदाहरण के लिए:

UserContrl1_LOadDataMethod()
{
    if(textbox1.text=="MyName") //<<======Now it wont give exception**
    {
        //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be
        //bound to grid at some later stage
        if(InvokeRequired)
        {
            // after we've done all the processing, 
            this.Invoke(new MethodInvoker(delegate {
                // load the control with the appropriate data
            }));
            return;
        }
    }
}

1
जब से मैंने C # प्रोग्रामिंग की है, तब से कुछ समय हो गया है, लेकिन MSDN लेख और मेरे ज्ञानपूर्ण ज्ञान के आधार पर, यह ऐसा दिखता है।
जेफ हबार्ड

1
अंतर है, BeginInvoke () एसिंक्रोनस है, जबकि Invoke () सिंक्रोनस चलता है। stackoverflow.com/questions/229554/…
frzsombor

178

UI में थ्रेडिंग मॉडल

बुनियादी अवधारणाओं को समझने के लिए कृपया UI अनुप्रयोगों में थ्रेडिंग मॉडल पढ़ें । लिंक पृष्ठ पर नेविगेट करता है जो WPF थ्रेडिंग मॉडल का वर्णन करता है। हालाँकि, Windows प्रपत्र समान विचार का उपयोग करता है।

यूआई थ्रेड

  • केवल एक थ्रेड (UI थ्रेड) है, जिसे System.Windows.Forms.Control और उसके उप-वर्ग के सदस्यों तक पहुँचने की अनुमति है ।
  • System.Windows के सदस्य का उपयोग करने का प्रयास करें। UI थ्रेड की तुलना में विभिन्न थ्रेड से कॉन्ट्रोल क्रॉस-थ्रेड अपवाद का कारण होगा।
  • चूंकि केवल एक धागा है, सभी UI संचालन को उस थ्रेड में कार्य आइटम के रूप में पंक्तिबद्ध किया जाता है:

यहाँ छवि विवरण दर्ज करें

  • यदि UI थ्रेड के लिए कोई काम नहीं है, तो बेकार अंतराल हैं जो कि एक यूआई-संबंधित कंप्यूटिंग द्वारा उपयोग किया जा सकता है।
  • करने के लिए उपयोग का उल्लेख किया अंतराल क्रम में उपयोग System.Windows.Forms.Control.Invoke या System.Windows.Forms.Control.BeginInvoke तरीके:

यहाँ छवि विवरण दर्ज करें

InInvoke और Invoke मेथड

  • जिस विधि को लागू किया जा रहा है उसका कंप्यूटिंग ओवरहेड छोटा होना चाहिए और साथ ही इवेंट हैंडलर विधियों की ओवरहेड गणना करना चाहिए क्योंकि यूआई थ्रेड का उपयोग वहां किया जाता है - वही जो उपयोगकर्ता इनपुट को संभालने के लिए जिम्मेदार है। भले ही यह System.Windows.Forms.Control.Invoke या System.Windows.Forms.Control.BeginInvoke है
  • कंप्यूटिंग महंगा ऑपरेशन करने के लिए हमेशा अलग थ्रेड का उपयोग करें। चूंकि .NET 2.0 बैकग्राउंडवॉकर विंडोज फॉर्म में महंगे ऑपरेशन करने के लिए समर्पित है। हालाँकि नए समाधानों में आपको यहाँ बताए गए async-wait पैटर्न का उपयोग करना चाहिए ।
  • केवल उपयोगकर्ता इंटरफ़ेस अद्यतन करने के लिए System.Windows.Forms.Control.Invoke या System.Windows.Forms.Control.BeginInvoke विधियों का उपयोग करें । यदि आप उन्हें भारी गणना के लिए उपयोग करते हैं, तो आपका आवेदन अवरुद्ध हो जाएगा:

यहाँ छवि विवरण दर्ज करें

आह्वान

यहाँ छवि विवरण दर्ज करें

BeginInvoke

  • System.Windows.Forms.Control.BeginInvoke अलग थ्रेड के कारण प्रतीक्षा करने का तरीका पूरा नहीं होने तक इंतजार नहीं करता है:

यहाँ छवि विवरण दर्ज करें

कोड समाधान

प्रश्न पर उत्तर पढ़ें सी # में एक और धागे से जीयूआई कैसे अपडेट करें? । C # 5.0 और .NET 4.5 के लिए अनुशंसित समाधान यहां है



72

आप केवल उपयोग करना चाहते हैं Invokeया BeginInvokeकाम की न्यूनतम टुकड़े के लिए यूआई बदलने के लिए आवश्यक। आपकी "भारी" विधि को किसी अन्य थ्रेड (जैसे के माध्यम से BackgroundWorker) पर निष्पादित करना चाहिए, लेकिन फिर यूआई को अपडेट करने के लिए Control.Invoke/ Control.BeginInvokeबस का उपयोग करना चाहिए । इस तरह से यूआई घटनाओं आदि को संभालने के लिए आपका यूआई धागा मुक्त हो जाएगा।

एक WinForms उदाहरण के लिए मेरा थ्रेडिंग लेख देखें - हालांकि लेख दृश्य पर आने से पहले लिखा गया था , और मुझे डर है कि मैंने इसे उस संबंध में अपडेट नहीं किया है। केवल कॉलबैक को थोड़ा सरल करता है।BackgroundWorkerBackgroundWorker


यहाँ इस हालत में मेरा। यूआई भी नहीं बदल रहा है। मैं सिर्फ बच्चे के धागे से इसके वर्तमान मूल्यों तक पहुंचता हूं। किसी भी सुझाव को लागू करने के लिए hw
Prerak K

1
तुम अभी भी यूआई धागा पर मार्शल करने की जरूरत है यहां तक ​​कि सिर्फ संपत्तियों तक पहुँचने के लिए। यदि आपकी विधि तब तक जारी नहीं रह सकती है जब तक कि मूल्य तक पहुँचा नहीं जाता है, तो आप एक प्रतिनिधि का उपयोग कर सकते हैं जो मान लौटाता है। लेकिन हाँ, UI थ्रेड के माध्यम से जाना।
जॉन स्कीट

हाय जॉन, मुझे विश्वास है कि तुम मुझे सही दिशा में ले जा रहे हो। हां, मुझे इसके बिना मूल्य की आवश्यकता है क्योंकि मैं आगे नहीं बढ़ सकता। क्या आप उस Using एक प्रतिनिधि का उपयोग करके जो कि एक मान लौटाते हैं ’पर ग्रहण लगा सकते हैं। धन्यवाद
Prerak कश्मीर

1
एक प्रतिनिधि का उपयोग करें जैसे फंक <string>: string text = textbox1.Invoke ((Func <string>) () => textbox1.Text); (यह मानते हुए कि आप C # 3.0 का उपयोग कर रहे हैं - आप अन्यथा एक अनाम विधि का उपयोग कर सकते हैं।)
जॉन स्कीट

45

मैं अब बहुत देर से जानता हूं। हालाँकि आज भी अगर आपको क्रॉस थ्रेड कंट्रोल तक पहुँचने में परेशानी हो रही है? यह अब तक का सबसे छोटा जवाब है: पी

Invoke(new Action(() =>
                {
                    label1.Text = "WooHoo!!!";
                }));

यह है कि मैं कैसे एक सूत्र से किसी भी रूप नियंत्रण का उपयोग।


1
यह मुझे देता है Invoke or BeginInvoke cannot be called on a control until the window handle has been created। मैंने इसे यहाँ
रुपये

42

मुझे इस समस्या का सामना करना पड़ा FileSystemWatcherऔर पाया कि निम्नलिखित कोड ने इस समस्या को हल कर दिया है:

fsw.SynchronizingObject = this

नियंत्रण तब घटनाओं से निपटने के लिए वर्तमान फॉर्म ऑब्जेक्ट का उपयोग करता है, और इसलिए उसी थ्रेड पर होगा।


2
इससे मेरी बेकन बच गई। में VB.NET मैं इस्तेमाल किया.SynchronizingObject = Me
codingcoding

20

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

public static class Extensions
{
    public static void Invoke<TControlType>(this TControlType control, Action<TControlType> del) 
        where TControlType : Control
        {
            if (control.InvokeRequired)
                control.Invoke(new Action(() => del(control)));
            else
                del(control);
    }
}

और फिर आप बस यह कर सकते हैं:

textbox1.Invoke(t => t.Text = "A");

कोई और अधिक गड़बड़ नहीं है - सरल।


यहाँ 't' क्या है
रावत

@Rawat tइस मामले में हो जाएगा textbox1- यह एक तर्क के रूप में पारित किया है
रोब

17

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

हालाँकि, आपके मामले में आपने जो भी किया है वह लंबे समय तक चलने वाला तरीका है जो मुख्य थ्रेड पर वापस जाता है। बेशक, यह वास्तव में नहीं है कि आप क्या करना चाहते हैं। आपको इस पर थोड़ा पुनर्विचार करने की आवश्यकता है, ताकि आप मुख्य सूत्र पर जो कुछ कर रहे हैं, वह यहाँ और वहाँ एक त्वरित संपत्ति स्थापित कर रहा है।


15

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


10

Async / Await और कॉलबैक का उपयोग करके एक नया रूप। यदि आप अपनी परियोजना में विस्तार विधि रखते हैं तो आपको केवल एक पंक्ति की आवश्यकता होती है।

/// <summary>
/// A new way to use Tasks for Asynchronous calls
/// </summary>
public class Example
{
    /// <summary>
    /// No more delegates, background workers etc. just one line of code as shown below
    /// Note it is dependent on the XTask class shown next.
    /// </summary>
    public async void ExampleMethod()
    {
        //Still on GUI/Original Thread here
        //Do your updates before the next line of code
        await XTask.RunAsync(() =>
        {
            //Running an asynchronous task here
            //Cannot update GUI Thread here, but can do lots of work
        });
        //Can update GUI/Original thread on this line
    }
}

/// <summary>
/// A class containing extension methods for the Task class 
/// Put this file in folder named Extensions
/// Use prefix of X for the class it Extends
/// </summary>
public static class XTask
{
    /// <summary>
    /// RunAsync is an extension method that encapsulates the Task.Run using a callback
    /// </summary>
    /// <param name="Code">The caller is called back on the new Task (on a different thread)</param>
    /// <returns></returns>
    public async static Task RunAsync(Action Code)
    {
        await Task.Run(() =>
        {
            Code();
        });
        return;
    }
}

आप एक्सटेंशन विधि में अन्य चीजें जोड़ सकते हैं जैसे कि इसे आज़माएं / कैच करें स्टेटमेंट में लपेटकर, कॉलर को यह बताने की अनुमति देता है कि पूरा होने के बाद किस तरह से लौटना है, कॉलर को एक अपवाद कॉलबैक:

ट्राई कैच, ऑटो एक्सेप्शन लॉगिंग और कॉलबैक जोड़ना

    /// <summary>
    /// Run Async
    /// </summary>
    /// <typeparam name="T">The type to return</typeparam>
    /// <param name="Code">The callback to the code</param>
    /// <param name="Error">The handled and logged exception if one occurs</param>
    /// <returns>The type expected as a competed task</returns>

    public async static Task<T> RunAsync<T>(Func<string,T> Code, Action<Exception> Error)
    {
       var done =  await Task<T>.Run(() =>
        {
            T result = default(T);
            try
            {
               result = Code("Code Here");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unhandled Exception: " + ex.Message);
                Console.WriteLine(ex.StackTrace);
                Error(ex);
            }
            return result;

        });
        return done;
    }
    public async void HowToUse()
    {
       //We now inject the type we want the async routine to return!
       var result =  await RunAsync<bool>((code) => {
           //write code here, all exceptions are logged via the wrapped try catch.
           //return what is needed
           return someBoolValue;
       }, 
       error => {

          //exceptions are already handled but are sent back here for further processing
       });
        if (result)
        {
            //we can now process the result because the code above awaited for the completion before
            //moving to this statement
        }
    }

10

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

CheckForIllegalCrossThreadCalls = false

में Form1()निर्माता।


9

किसी अन्य थ्रेड से ऑब्जेक्ट्स को संशोधित करने के लिए सबसे सरल (मेरी राय में) तरीके का पालन करें:

using System.Threading.Tasks;
using System.Threading;

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

        private void button1_Click(object sender, EventArgs e)
        {
            Action<string> DelegateTeste_ModifyText = THREAD_MOD;
            Invoke(DelegateTeste_ModifyText, "MODIFY BY THREAD");
        }

        private void THREAD_MOD(string teste)
        {
            textBox1.Text = teste;
        }
    }
}

सरल ! धन्यवाद ।
अली एस्माईली

8

आपको बैकग्राउंडर उदाहरण देखने की जरूरत है:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx विशेष रूप से यह UI परत के साथ कैसे इंटरैक्ट करता है। आपकी पोस्टिंग के आधार पर, यह आपके मुद्दों का जवाब देता है।


7

मुझे इसके लिए एक ज़रूरत महसूस हुई जबकि एक स्टूडियो स्टूडियो में xamarin stuidio के बाहर एक विजुअल स्टूडियो winforms प्रोटोटाइप प्रोजेक्ट में iOS-फ़ोन मोनोटच ऐप कंट्रोलर को प्रोग्रामिंग करते हुए। संभव के रूप में संभव के रूप में xamarin स्टूडियो पर वीएस में कार्यक्रम का जिक्र करते हुए, मैं चाहता था कि नियंत्रक को फोन ढांचे से पूरी तरह से विघटित किया जाए। इस तरह से एंड्रॉइड और विंडोज फोन जैसे अन्य फ्रेमवर्क के लिए इसे लागू करना भविष्य के उपयोग के लिए बहुत आसान होगा।

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

public partial class Form1 : Form
{
    private ExampleController.MyController controller;

    public Form1()
    {          
        InitializeComponent();
        controller = new ExampleController.MyController((ISynchronizeInvoke) this);
        controller.Finished += controller_Finished;
    }

    void controller_Finished(string returnValue)
    {
        label1.Text = returnValue; 
    }

    private void button1_Click(object sender, EventArgs e)
    {
        controller.SubmitTask("Do It");
    }
}

जीयूआई फॉर्म अनजान है जो नियंत्रक अतुल्यकालिक कार्यों को चला रहा है।

public delegate void FinishedTasksHandler(string returnValue);

public class MyController
{
    private ISynchronizeInvoke _syn; 
    public MyController(ISynchronizeInvoke syn) {  _syn = syn; } 
    public event FinishedTasksHandler Finished; 

    public void SubmitTask(string someValue)
    {
        System.Threading.ThreadPool.QueueUserWorkItem(state => submitTask(someValue));
    }

    private void submitTask(string someValue)
    {
        someValue = someValue + " " + DateTime.Now.ToString();
        System.Threading.Thread.Sleep(5000);
//Finished(someValue); This causes cross threading error if called like this.

        if (Finished != null)
        {
            if (_syn.InvokeRequired)
            {
                _syn.Invoke(Finished, new object[] { someValue });
            }
            else
            {
                Finished(someValue);
            }
        }
    }
}

6

यदि आप जिस वस्तु के साथ काम कर रहे हैं, वह वैकल्पिक तरीका नहीं है

(InvokeRequired)

यह उपयोगी है यदि आप मुख्य रूप के अलावा किसी वर्ग में मुख्य रूप के साथ काम कर रहे हैं जो मुख्य रूप में है, लेकिन InvokeRequired नहीं है

delegate void updateMainFormObject(FormObjectType objectWithoutInvoke, string text);

private void updateFormObjectType(FormObjectType objectWithoutInvoke, string text)
{
    MainForm.Invoke(new updateMainFormObject(UpdateObject), objectWithoutInvoke, text);
}

public void UpdateObject(ToolStripStatusLabel objectWithoutInvoke, string text)
{
    objectWithoutInvoke.Text = text;
}

यह ऊपर के समान ही काम करता है, लेकिन यह एक अलग दृष्टिकोण है यदि आपके पास कोई वस्तु नहीं है जो कि इनोकाइरेक्वायर्ड है, लेकिन मेनफोर्म तक पहुंच नहीं है


5

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

हेल्पर विधि

/// <summary>
/// Helper method to determin if invoke required, if so will rerun method on correct thread.
/// if not do nothing.
/// </summary>
/// <param name="c">Control that might require invoking</param>
/// <param name="a">action to preform on control thread if so.</param>
/// <returns>true if invoke required</returns>
public bool ControlInvokeRequired(Control c, Action a)
{
    if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate
    {
        a();
    }));
    else return false;

    return true;
}

नमूना उपयोग

// usage on textbox
public void UpdateTextBox1(String text)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
    textBox1.Text = ellapsed;
}

//Or any control
public void UpdateControl(Color c, String s)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(myControl, () => UpdateControl(c, s))) return;
    myControl.Text = s;
    myControl.BackColor = c;
}


5

उदाहरण के लिए, UI थ्रेड के नियंत्रण से पाठ प्राप्त करने के लिए:

Private Delegate Function GetControlTextInvoker(ByVal ctl As Control) As String

Private Function GetControlText(ByVal ctl As Control) As String
    Dim text As String

    If ctl.InvokeRequired Then
        text = CStr(ctl.Invoke(
            New GetControlTextInvoker(AddressOf GetControlText), ctl))
    Else
        text = ctl.Text
    End If

    Return text
End Function

3

एक ही सवाल: कैसे-से-अद्यतन-गुई-से-एक-धागा-में-सी

दो तरीके:

  1. E.result में मान लौटाएँ और इसका उपयोग yout textbox value को backgroundWorker_RunWorkerComplex घटना में सेट करने के लिए करें

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

उदाहरण:

public  class data_holder_for_controls
{
    //it will hold value for your label
    public  string status = string.Empty;
}

class Demo
{
    public static  data_holder_for_controls d1 = new data_holder_for_controls();
    static void Main(string[] args)
    {
        ThreadStart ts = new ThreadStart(perform_logic);
        Thread t1 = new Thread(ts);
        t1.Start();
        t1.Join();
        //your_label.Text=d1.status; --- can access it from any thread 
    }

    public static void perform_logic()
    {
        //put some code here in this function
        for (int i = 0; i < 10; i++)
        {
            //statements here
        }
        //set result in status variable
        d1.status = "Task done";
    }
}



0

इस समस्या के आसपास काम करने का सरल और पुन: प्रयोज्य तरीका।

विस्तार विधि

public static class FormExts
{
    public static void LoadOnUI(this Form frm, Action action)
    {
        if (frm.InvokeRequired) frm.Invoke(action);
        else action.Invoke();
    }
}

नमूना उपयोग

private void OnAnyEvent(object sender, EventArgs args)
{
    this.LoadOnUI(() =>
    {
        label1.Text = "";
        button1.Text = "";
    });
}

-3

क्रॉस थ्रेड संचालन के लिए दो विकल्प हैं।

Control.InvokeRequired Property 

और दूसरा उपयोग करना है

SynchronizationContext Post Method

Control.InvokeRequired केवल तभी उपयोगी होता है जब नियंत्रण वर्ग से विरासत में प्राप्त किए गए कार्य नियंत्रण, जबकि SynchronizationContext का उपयोग कहीं भी किया जा सकता है। कुछ उपयोगी जानकारी निम्नलिखित लिंक के रूप में है

क्रॉस थ्रेड अपडेट यूआई | नेट

सिंक्रोनाइज़ेशन कॉन्टेक्स्ट का उपयोग करके क्रॉस थ्रेड अपडेट यूआई | नेट

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