ক্রস-থ্রেড অপারেশন বৈধ নয়: থ্রেডটি তৈরি হওয়া থ্রেড ব্যতীত অন্য কোনও থ্রেড থেকে নিয়ন্ত্রণ করা


584

আমার একটা দৃশ্য আছে (উইন্ডোজ ফর্ম, সি #,। নেট)

  1. একটি প্রধান ফর্ম রয়েছে যা কিছু ব্যবহারকারীর নিয়ন্ত্রণকে হোস্ট করে।
  2. ব্যবহারকারীর নিয়ন্ত্রণ কিছু ভারী ডেটা অপারেশন করে, যেমন আমি যদি সরাসরি UserControl_Loadপদ্ধতিটিকে কল করি তবে ইউআই লোড পদ্ধতি কার্যকর করার সময়কালের জন্য প্রতিক্রিয়াহীন হয়ে যায়।
  3. এটিকে কাটিয়ে উঠতে আমি বিভিন্ন থ্রেডে ডেটা লোড করি (বিদ্যমান কোডটি যতটা পারি সামান্য পরিবর্তন করার চেষ্টা করছি)
  4. আমি একটি পটভূমি কর্মী থ্রেড ব্যবহার করেছি যা ডেটা লোড করা হবে এবং হয়ে গেলে অ্যাপ্লিকেশনটি এটির কাজটি জানিয়েছে।
  5. এখন আসল সমস্যা। সমস্ত ইউআই (মূল ফর্ম এবং তার শিশু ব্যবহারকারী নিয়ন্ত্রণ) প্রাথমিক মূল থ্রেডে তৈরি হয়েছিল। ব্যবহারকারী নিয়ন্ত্রণের লোড পদ্ধতিতে আমি ব্যবহারকারীকন্ট্রোলের কিছু নিয়ন্ত্রণের (যেমন টেক্সটবক্সের) মানগুলির ভিত্তিতে ডেটা আনছি।

সিউডোকোডটি দেখতে এমন হবে:

কোড ২

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.
    }
}

এটি দেওয়া ব্যতিক্রম ছিল

ক্রস-থ্রেড অপারেশন বৈধ নয়: থ্রেডটি তৈরি হওয়া থ্রেড ব্যতীত অন্য কোনও থ্রেড থেকে নিয়ন্ত্রণ করা।

এ সম্পর্কে আরও জানতে আমি কিছু গুগলিং করেছি এবং নীচের কোডটি ব্যবহার করার মতো একটি পরামর্শ এলো

কোড 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 লাইনটি কার্যকর করার কারণে এটি বলে মনে হচ্ছে। লোডিংয়ের কাজটি আবার প্যারেন্ট থ্রেড দ্বারা সম্পন্ন হয় এবং তৃতীয়টি নয় sp

আমি বুঝতে পারি না আমি এটি সঠিক বা ভুল বুঝতে পেরেছি কিনা। আমি থ্রেডিংয়ে নতুন।

আমি কীভাবে এটি সমাধান করব এবং এছাড়াও ব্লক হলে # 1 লাইন কার্যকর করার কী প্রভাব রয়েছে?

পরিস্থিতিটি হ'ল : আমি কোনও নিয়ন্ত্রণের মানের ভিত্তিতে বৈশ্বিক চলকগুলিতে ডেটা লোড করতে চাই। আমি শিশু থ্রেড থেকে কোনও নিয়ন্ত্রণের মান পরিবর্তন করতে চাই না। আমি কোনও সন্তানের সুতো থেকে এটি করতে যাচ্ছি না।

সুতরাং শুধুমাত্র মানটি অ্যাক্সেস করা যাতে সম্পর্কিত ডেটাবেস থেকে আনতে পারে।


এই ত্রুটির আমার বিশেষ উদাহরণের জন্য, আমি কোডটির ডেটা-নিবিড় অংশগুলি পরিচালনা করতে ফর্মটিতে একটি ব্যাকগ্রাউন্ড ওয়ার্কার ব্যবহার করার মত কাজটি পেয়েছি। (অর্থাত্ সমস্ত সমস্যার কোডটি ব্যাকগ্রাউন্ডে ওয়ার্কারআর_ডোওয়ার্ক () পদ্ধতিতে রাখুন এবং এটি ব্যাকগ্রাউন্ড ওয়ার্কার 1 এর মাধ্যমে কল করুন un রুন ওয়ার্কারএ্যাসেন্স ()) ... এই দুটি উত্স আমাকে সঠিক দিক নির্দেশ করেছে: স্ট্যাকওভারফ্লো / সিকিউশনস / 4806742/… youtube.com/ দেখুন? v = MLrrbG6V1zM
গিয়োলিয়া

উত্তর:


433

অনুযায়ী Prerak কে এর আপডেট মন্তব্য (যেহেতু মুছে ফেলা হয়েছে):

আমার ধারণা আমি সঠিকভাবে প্রশ্ন উপস্থাপন করিনি।

পরিস্থিতিটি হ'ল: আমি কোনও নিয়ন্ত্রণের মানের উপর ভিত্তি করে বৈশ্বিক চলকগুলিতে ডেটা লোড করতে চাই। আমি শিশু থ্রেড থেকে কোনও নিয়ন্ত্রণের মান পরিবর্তন করতে চাই না। আমি কোনও সন্তানের সুতো থেকে এটি করতে যাচ্ছি না।

সুতরাং কেবলমাত্র মানটি অ্যাক্সেস করা যাতে ডাটাবেস থেকে সম্পর্কিত ডেটা আনা যায়।

তারপরে যে সমাধানটি চান তা দেখতে এমন হওয়া উচিত:

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
আমি সি # প্রোগ্রামিং করার পরে এখন অনেকক্ষণ হয়ে গেছে, তবে এমএসডিএন নিবন্ধ এবং আমার জাগতিক জ্ঞানের উপর ভিত্তি করে এটি দেখতে এটির মতো দেখাচ্ছে।
জেফ হাবার্ড

1
পার্থক্যটি হ'ল বিগিনিউভোক () হ'ল অ্যাসিনক্রোনাস এবং ইনভোক () সিঙ্ক্রোনিকভাবে চলমান। stackoverflow.com/questions/229554/...
frzsombor

178

ইউআই মধ্যে থ্রেডিং মডেল

প্রাথমিক ধারণাটি বুঝতে দয়া করে ইউআই অ্যাপ্লিকেশনগুলিতে থ্রেডিং মডেলটি পড়ুন । লিঙ্কটি এমন পৃষ্ঠায় নেভিগেট করে যা ডাব্লুপিএফ থ্রেডিং মডেলটি বর্ণনা করে। যাইহোক, উইন্ডোজ ফর্মগুলি একই ধারণাটি ব্যবহার করে।

ইউআই থ্রেড

  • এখানে কেবলমাত্র একটি থ্রেড (ইউআই থ্রেড) রয়েছে, যা সিস্টেম.বাইন্ডস.ফর্মস.কন্ট্রোল এবং এর সাবক্লাসের সদস্যদের অ্যাক্সেসের অনুমতিপ্রাপ্ত
  • ইউএসআই থ্রেডের চেয়ে আলাদা থ্রেড থেকে System.Windows . Forms.Control এর সদস্য অ্যাক্সেসের চেষ্টা ক্রস-থ্রেড ব্যতিক্রম ঘটায়।
  • যেহেতু শুধুমাত্র একটি থ্রেড রয়েছে, সমস্ত UI ক্রিয়াকলাপগুলি সেই থ্রেডে কাজের আইটেম হিসাবে সারিবদ্ধ রয়েছে:

এখানে চিত্র বর্ণনা লিখুন

  • যদি ইউআই থ্রেডের জন্য কোনও কাজ না হয়, তবে নিষ্ক্রিয় ফাঁকগুলি নট-ইউআই সম্পর্কিত কম্পিউটারের দ্বারা ব্যবহৃত হতে পারে।
  • উল্লিখিত ফাঁকগুলি ব্যবহার করার জন্য System.Windows. Forms.Control.Invoke বা System.Windows. Forms.Control.BeginInvoke পদ্ধতি ব্যবহার করুন:

এখানে চিত্র বর্ণনা লিখুন

বিগেইনভোক এবং ইনভোক পদ্ধতিগুলি

  • অনুরোধ করা হচ্ছে পদ্ধতির কম্পিউটিং ওভারহেড ছোট হওয়ার সাথে সাথে ইভেন্ট হ্যান্ডলার পদ্ধতির ওভারহেডের কম্পিউটিং করা উচিত কারণ সেখানে ইউআই থ্রেড ব্যবহৃত হয় - এটিই যা ব্যবহারকারীর ইনপুট পরিচালনা করার জন্য দায়ী। এটি যদি System.Windows . Forms.Control.Invoke বা System.Windows . Forms.Control.BeginInvoke হয় তা নির্বিশেষে
  • কম্পিউটিং ব্যয়বহুল ক্রিয়াকলাপ সম্পাদন করতে সর্বদা পৃথক থ্রেড ব্যবহার করুন। .NET 2.0 ব্যাকগ্রাউন্ড ওয়ার্কার উইন্ডোজ ফর্মগুলিতে ব্যয়বহুল ক্রিয়াকলাপ সম্পাদন করতে উত্সর্গীকৃত। তবে নতুন সমাধানগুলিতে আপনার এখানে বর্ণিত হিসাবে অ্যাসিঙ্ক-অপেক্ষার প্যাটার্নটি ব্যবহার করা উচিত ।
  • ব্যবহারের System.Windows.Forms.Control.Invoke বা System.Windows.Forms.Control.BeginInvoke পদ্ধতি শুধুমাত্র একটি ইউজার ইন্টারফেস আপডেট করতে। যদি আপনি এগুলি ভারী গণনার জন্য ব্যবহার করেন তবে আপনার অ্যাপ্লিকেশনটি ব্লক করবে:

এখানে চিত্র বর্ণনা লিখুন

ডাকা

  • System.Windows. Forms.Control.Onvoke এর জন্য অনুরোধ করা পদ্ধতিটি শেষ না হওয়া পর্যন্ত পৃথক থ্রেড অপেক্ষা করতে হবে:

এখানে চিত্র বর্ণনা লিখুন

BeginInvoke

এখানে চিত্র বর্ণনা লিখুন

কোড সমাধান

প্রশ্নের উত্তর পড়ুন কীভাবে সি # তে অন্য থ্রেড থেকে জিইউআই আপডেট করবেন? । সি # 5.0 এবং .NET 4.5 এর জন্য প্রস্তাবিত সমাধানটি এখানে



72

আপনি কেবল ইউআই পরিবর্তন করতে প্রয়োজন Invokeবা BeginInvokeখালি ন্যূনতম কাজের টুকরোটি ব্যবহার করতে চান । আপনার "ভারী" পদ্ধতিটি অন্য থ্রেডে চালিত করা উচিত (উদাহরণস্বরূপ BackgroundWorker) তবে তারপরে Control.Invoke/ Control.BeginInvokeকেবল ইউআই আপডেট করার জন্য ব্যবহার করুন । এইভাবে আপনার ইউআই থ্রেডটি ইউআই ইভেন্টগুলি হ্যান্ডল করার জন্য মুক্ত হবে etc.

একটি উইনফর্মের উদাহরণের জন্য আমার থ্রেডিং নিবন্ধটি দেখুন - যদিও নিবন্ধটি ঘটনাস্থলে আসার আগে লেখা হয়েছিল , এবং আমি আশঙ্কা করছি যে আমি এটি সে সম্পর্কে আপডেট করেছি না। কেবল কলব্যাকটি কিছুটা সরল করে।BackgroundWorkerBackgroundWorker


আমার এই অবস্থা। আমি এমনকি ইউআই পরিবর্তন করছি না। আমি কেবলমাত্র তার বর্তমান মানগুলি শিশু থ্রেড থেকে অ্যাক্সেস করছি। কোনও পরামর্শ hw বাস্তবায়নের জন্য
প্রেরাক কে

1
কেবলমাত্র বৈশিষ্ট্য অ্যাক্সেস করার জন্য আপনাকে এখনও ইউআই থ্রেডে মার্শাল করতে হবে। যদি মানটি অ্যাক্সেস না হওয়া অবধি আপনার পদ্ধতি অব্যাহত না রাখতে পারে তবে আপনি কোনও প্রতিনিধি ব্যবহার করতে পারেন যা মানটি ফেরত দেয়। তবে হ্যাঁ, ইউআই থ্রেড দিয়ে যান।
জন স্কিটি

হাই জোন, আমি বিশ্বাস করি আপনি আমাকে সঠিক দিকে নিয়ে যাচ্ছেন। হ্যাঁ, মূল্য ছাড়াই আমার দরকার, আমি আর এগিয়ে যেতে পারি না। দয়া করে আপনি 'একটি ডেলিগেট যা ব্যবহার করে কোনও মান প্রত্যাখ্যান করে' তা ব্যাখ্যা করতে পারেন। ধন্যবাদ
প্রেরাক কে

1
ফানক <স্ট্রিং> এর মতো একটি প্রতিনিধি ব্যবহার করুন: স্ট্রিং টেক্সট = টেক্সটবক্স 1. ইনভোক করুন ((ফানক <স্ট্রিং>) () => পাঠ্যবক্স 1. পাঠ্য); (এটি ধরে নিয়েছে যে আপনি সি # 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
এটি আমার বেকন সংরক্ষণ করেছে .SynchronizingObject = Me
ভিবি.এনইটি

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");

চারপাশে আর গোলযোগ নেই - সহজ।


এখানে 'টি' কী
রাওয়াত

@Rawat tএই ক্ষেত্রে হতে হবে textbox1- এটা একটি আর্গুমেন্ট হিসাবে পাস হচ্ছে
রব

17

.NET- এ নিয়ন্ত্রণগুলি সাধারণত থ্রেড নিরাপদ থাকে না। এর অর্থ এটি যেখানে বাস করে তার চেয়ে অন্য কোনও থ্রেড থেকে আপনার কোনও নিয়ন্ত্রণ অ্যাক্সেস করা উচিত নয়। এটি পেতে, আপনাকে নিয়ন্ত্রণটি চালু করতে হবে যা আপনার ২ য় নমুনা চেষ্টা করছে।

তবে আপনার ক্ষেত্রে আপনি যা করেছেন তা হ'ল দীর্ঘ চলমান পদ্ধতিটি মূল থ্রেডে ফিরে যাওয়া। অবশ্যই, আপনি যা করতে চান তা আসলে তা নয়। আপনার এটিকে একটু পুনর্বিবেচনা করতে হবে যাতে আপনি মূল থ্রেডে যা করছেন তা এখানে এবং সেখানে একটি দ্রুত সম্পত্তি নির্ধারণ করছে।


15

ইউআই ক্রস-থ্রেডিং ইস্যুগুলির জন্য সবচেয়ে পরিষ্কার (এবং যথাযথ) সমাধান হ'ল সিঙ্ক্রোনাইজেশন কনটেক্সট ব্যবহার করা, একাধিক-থ্রেড অ্যাপ্লিকেশন নিবন্ধে ইউআইতে সিঙ্ক্রোনাইজিং কলগুলি দেখুন , এটি এটি খুব সুন্দরভাবে ব্যাখ্যা করেছে।


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;
        }
    }
}

সরল! ধন্যবাদ
আলী ইসমাiliলি

8

আপনাকে ব্যাকগ্রাউন্ড ওয়ার্কার উদাহরণটি দেখতে হবে:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx বিশেষত এটি কীভাবে UI স্তরটির সাথে ইন্টারেক্ট করে। আপনার পোস্টিংয়ের ভিত্তিতে, এটি আপনার সমস্যার উত্তর বলে মনে হচ্ছে।


7

Xamarin stuidio এর বাইরে একটি ভিজ্যুয়াল স্টুডিও উইনফর্মস প্রোটোটাইপ প্রকল্পে একটি আইওএস-ফোন মনোোটুচ অ্যাপ্লিকেশন কন্ট্রোলার প্রোগ্রাম করার সময় আমি এর প্রয়োজন খুঁজে পেয়েছি। যতটা সম্ভব এক্সআরমারিন স্টুডিওতে ওএসে প্রোগ্রামিংয়ের আগে, আমি চেয়েছিলাম যে কন্ট্রোলারটি ফোনের কাঠামো থেকে পুরোপুরি ডিউপলড হয়ে যায়। এটিকে অ্যান্ড্রয়েড এবং উইন্ডোজ ফোনের মতো অন্যান্য ফ্রেমওয়ার্কের জন্য এটি বাস্তবায়ন ভবিষ্যতের ব্যবহারের জন্য আরও সহজ হবে।

আমি এমন একটি সমাধান চেয়েছিলাম যেখানে জিইউআই প্রতিটি বোতাম ক্লিকের পিছনে ক্রস থ্রেডিং স্যুইচিং কোডের সাথে ডিল করার বোঝা ছাড়াই ইভেন্টগুলিতে প্রতিক্রিয়া জানাতে পারে। ক্লাসিক কোডটি সহজ রাখতে ক্লাস কন্ট্রোলারটিকে হ্যান্ডেল করতে দিন। আপনি জিইউআইতে সম্ভবত অনেকগুলি ইভেন্ট থাকতে পারে যেখানে আপনি এটি ক্লাসের এক জায়গায় হ্যান্ডেল করতে পারলে ক্লিনার হবে। আমি কোনও মাল্টি থিয়েডিং বিশেষজ্ঞ নই, যদি এটি ত্রুটিযুক্ত হয় তবে আমাকে জানান।

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");
    }
}

জিইউআই ফর্মটি অজানা the

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)

আপনি যদি মূল ফর্মটিতে থাকা কোনও অবজেক্টের সাথে মূল ফর্ম ব্যতীত অন্য শ্রেণিতে প্রধান ফর্মের সাথে কাজ করছেন তবে ইনভেকের্কায়ার্ড নেই তবে এটি কার্যকর

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;
}

এটি উপরের মতো একই রকম কাজ করে, তবে যদি আপনার কাছে অনুরোধযুক্ত কোনও জিনিস না থাকে তবে মেইনফোর্মে অ্যাক্সেস থাকে তবে এটি আলাদা পদ্ধতি is


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

উদাহরণস্বরূপ, ইউআই থ্রেডের একটি নিয়ন্ত্রণ থেকে পাঠ্যটি পেতে:

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. ইআরসাল্টে মান ফেরত দিন এবং পটভূমিতে আপনার পাঠ্যবাক্সের মান সেট করতে এটি ব্যবহার করুন ওয়ার্ক_রুনকার্কর সমাপ্ত ইভেন্ট

  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

কন্ট্রোল.ভুক্তিপ্রাপ্ত কেবল তখনই কার্যকর যখন কন্ট্রোল ক্লাস থেকে উত্তরাধিকার সূত্রে ওয়ার্কিং কন্ট্রোলস সিঙ্ক্রোনাইজেশন কনটেক্সট যে কোনও জায়গায় ব্যবহার করা যেতে পারে। কিছু দরকারী তথ্য নিম্নলিখিত লিঙ্ক হিসাবে

ক্রস থ্রেড আপডেট ইউআই | নেট

সিঙ্ক্রোনাইজেশন কনটেক্সট ব্যবহার করে ক্রস থ্রেড আপডেট ইউআই নেট

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.