ইনভোকেরইওয়ার্ড কোড প্যাটার্নটি স্বয়ংক্রিয় করা


179

ইভেন্ট-চালিত জিইউআই কোডে যেখানে নিম্নলিখিত কোড প্যাটার্নটি লিখতে হবে তার জন্য আমি কতক্ষণ বেদনাদায়ক সচেতন হয়েছি

private void DoGUISwitch() {
    // cruisin for a bruisin' through exception city
    object1.Visible = true;
    object2.Visible = false;
}

হয়ে:

private void DoGUISwitch() {
    if (object1.InvokeRequired) {
        object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
    } else {
        object1.Visible = true;
        object2.Visible = false;
    }
}

এটি সি # তে একটি বিশ্রী প্যাটার্ন, উভয় মনে রাখতে এবং টাইপ করতে। কেউ কি কোনও ধরণের শর্টকাট নিয়ে এসেছেন বা এমন একটি নির্মাণ করেছেন যা এটি একটি ডিগ্রীতে স্বয়ংক্রিয়ভাবে চলে? এটি দুর্দান্ত হবে যদি কোনও object1.InvokeIfNecessary.visible = trueধরণের শর্টকাটের মতো এই সমস্ত অতিরিক্ত কাজ না করেই এই চেকটি করে এমন বস্তুর সাথে কোনও ফাংশন সংযুক্ত করার উপায় ছিল ।

পূর্ববর্তী উত্তরগুলি প্রতিবার কেবল ইনভোক () কল করার অযৌক্তিকতা নিয়ে আলোচনা করেছে এবং তারপরেও ইনভোক () সিনট্যাক্স উভয়ই অকার্যকর এবং এর সাথে মোকাবিলা করার জন্য এখনও বিশ্রী।

সুতরাং, কেউ কি কোনও শর্টকাট বের করেছে?


2
আমি একই জিনিসটি অবাক করেছি, তবে ডব্লিউপিএফের ডিসপ্যাচারের জন্য। চেকএ্যাক্সেস ()।
টেলর লিজ

আমি আপনার object1.InvokeIfNecessary.Visible = trueলাইন দ্বারা অনুপ্রাণিত একটি বরং পাগল পরামর্শ ভেবেছি ; আমার আপডেট হওয়া উত্তরটি পরীক্ষা করে দেখুন এবং আপনার কী মনে হয় তা আমাকে জানান।
ড্যান টাও

1
ম্যাট ডেভিস প্রস্তাবিত পদ্ধতি বাস্তবায়নে সহায়তার জন্য একটি স্নিপেট যুক্ত করুন: আমার উত্তর দেখুন (দেরীতে তবে কেবল পরবর্তী পাঠকদের জন্য কীভাবে দেখানো হচ্ছে ;-))
অ্যারন গেজ

3
মাইক্রোসফ্ট .NET এ কেন সরল করার জন্য কিছুই করেনি তা আমি বুঝতে পারি না। থ্রেড থেকে ফর্মের প্রতিটি পরিবর্তনের জন্য প্রতিনিধি তৈরি করা সত্যিই বিরক্তিকর।
কামিল

@ কামিল আমি আর একমত হতে পারি না! এটি সর্বব্যাপী প্রদত্ত এই জাতীয় পর্যবেক্ষণ। কাঠামোর মধ্যে, যদি প্রয়োজন হয় কেবল থ্রেডিং পরিচালনা করুন। সুস্পষ্ট বলে মনে হচ্ছে।
স্টিভ সিনিক

উত্তর:


138

লি এর পদ্ধতির আরও সহজ করা যেতে পারে

public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
    // See Update 2 for edits Mike de Klerk suggests to insert here.

    if (control.InvokeRequired) {
        control.Invoke(action);
    } else {
        action();
    }
}

এবং এভাবে বলা যেতে পারে

richEditControl1.InvokeIfRequired(() =>
{
    // Do anything you want with the control here
    richEditControl1.RtfText = value;
    RtfHelpers.AddMissingStyles(richEditControl1);
});

প্রতিনিধিটির কাছে প্যারামিটার হিসাবে নিয়ন্ত্রণটি পাস করার দরকার নেই। সি # স্বয়ংক্রিয়ভাবে একটি বন্ধকরণ তৈরি করে ।


আপডেট :

আরও কয়েকটি পোস্টার অনুসারে Controlএটিকে সাধারণীকরণ করা যায় ISynchronizeInvoke:

public static void InvokeIfRequired(this ISynchronizeInvoke obj,
                                         MethodInvoker action)
{
    if (obj.InvokeRequired) {
        var args = new object[0];
        obj.Invoke(action, args);
    } else {
        action();
    }
}

ডনবয়েটনট উল্লেখ করেছেন যে ইন্টারফেসের বিপরীতে Controlএর ISynchronizeInvokeজন্য Invokeপরামিতি তালিকা হিসাবে পদ্ধতির জন্য একটি অবজেক্ট অ্যারের প্রয়োজন action


আপডেট 2

মাইক ডি ক্লার্ক প্রস্তাবিত সম্পাদনাগুলি (সন্নিবেশ পয়েন্টের জন্য 1 ম কোড স্নিপেটে মন্তব্য দেখুন):

// When the form, thus the control, isn't visible yet, InvokeRequired  returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
    System.Threading.Thread.Sleep(50);
}

এই পরামর্শ সম্পর্কে উদ্বেগের জন্য নীচে টুলমেকারস্টাইভের মন্তব্য দেখুন।


2
ISynchronizeInvokeপরিবর্তে ভাল না Control? (যশ জন স্কিট করার stackoverflow.com/questions/711408/... )
Odys

@odyodyodys: ভাল পয়েন্ট। আমি সম্পর্কে জানতাম না ISynchronizeInvoke। তবে এর থেকে প্রাপ্ত একমাত্র প্রকারটি (প্রতিফলকের মতে) Control, সুতরাং অ্যাডভান্টেজটি সীমাবদ্ধ।
অলিভিয়ার জ্যাকট-ডেসকোম্বেস

3
@ মাইক-ডি-ক্লার্ক, আপনার যোগ করার পরামর্শ সম্পর্কে আমি উদ্বিগ্ন while (!control.Visible) ..sleep..। আমার কাছে এটির একটি খারাপ কোড গন্ধ আছে, কারণ এটি একটি সম্ভাব্য সীমাহীন দেরি (সম্ভবত কিছু ক্ষেত্রে এমনকি একটি অসীম লুপ), কোডে কল রয়েছে যারা এই জাতীয় বিলম্বের আশা করছেন না (বা এমনকি কোনও অচলাবস্থাও নেই)। আইএমএইচও, যে কোনও ব্যবহারের জন্য Sleepপ্রতিটি কলারের দায়িত্ব হওয়া উচিত, বা পৃথক মোড়কের মধ্যে থাকা উচিত যা এর পরিণতি হিসাবে স্পষ্টভাবে চিহ্নিত করা উচিত। আইএমএইচও, সাধারণত "হার্ড ব্যর্থ হওয়া" (ব্যতিক্রম, পরীক্ষার সময় ধরা পড়া), বা নিয়ন্ত্রণ প্রস্তুত না হলে "কিছুই না করা" ভাল। মন্তব্য?
নির্মাতা স্টিভ

1
@ অলিভিয়ার জাকোট-ডেসকোম্বেস, আপনি যদি দয়া করে ব্যাখ্যা করেন যে থ্রেড।
সুধির ডটনে

1
InvokeRequiredকলিং থ্রেড নিয়ন্ত্রণ তৈরি করা থ্রেডের থেকে পৃথক কিনা তা জানায়। Invokeকলিং থ্রেড থেকে ক্রিয়াকলাপটি নিয়ন্ত্রণের থ্রেডে চালিত হয় যেখানে এটি কার্যকর করা হয়। এটি নিশ্চিত করে যে, উদাহরণস্বরূপ, একটি ক্লিক ইভেন্ট হ্যান্ডলার কখনই বাধা না দেয়।
অলিভিয়ার জ্যাকট-ডেসকোম্বেস

133

আপনি একটি এক্সটেনশন পদ্ধতি লিখতে পারেন:

public static void InvokeIfRequired(this Control c, Action<Control> action)
{
    if(c.InvokeRequired)
    {
        c.Invoke(new Action(() => action(c)));
    }
    else
    {
        action(c);
    }
}

এবং এটি এর মতো ব্যবহার করুন:

object1.InvokeIfRequired(c => { c.Visible = true; });

সম্পাদনা: সিম্পসন মন্তব্যগুলিতে যেমন উল্লেখ করেছেন আপনি স্বাক্ষরটিও এতে পরিবর্তন করতে পারেন:

public static void InvokeIfRequired<T>(this T c, Action<T> action) 
    where T : Control

সম্ভবত আমি খুব বোবা, কিন্তু এই কোডটি সংকলন করবে না। সুতরাং এটি আমার (VS2008) নির্মিত হিসাবে ঠিক করেছি।
অলিভার

5
কেবলমাত্র সম্পূর্ণতার জন্য: ডাব্লুপিএফ-তে একটি পৃথক প্রেরণ পদ্ধতি রয়েছে, তবে এটি বরং সাদৃশ্যপূর্ণ কাজ করে। আপনি এই এক্সটেনশন পদ্ধতিটি এখানে ব্যবহার করতে পারেন: সার্বজনীন স্ট্যাটিক শূন্যদল ইনভেকআইফরাইফায়ার্ড <T> (এই টি টিজার্ট, অ্যাকশন <T> aActionToExecute) যেখানে টি: ডিসপ্যাটচারঅবজেক্ট {if (aTarget.CheckAccess ()) A actionToExecute (aTarget); } অন্য {এটারাজেট.ডিসপ্যাচার.আনভোক (#ActionToExecute); }}
সাইমন ডি

1
আমি একটি উত্তর যুক্ত করেছি যা লি এর সমাধানটিকে সামান্যতম করে তোলে।
অলিভিয়ার জ্যাকট-ডেসকোম্বেস

হাই, আমি যেহেতু অবিস্মরণীয় কিছু ব্যবহার করছি সেখানে এই জেনেরিক প্রয়োগ থেকে একটি বড় সমস্যা আসতে পারে। যদি নিয়ন্ত্রণটি ডিসপোজ / ডিসপোজ করা হয় তবে আপনি একটি অবজেক্ট ডিসপোজড এক্সসেপশন পাবেন।
অফার

1
@ অফলার - আচ্ছা যদি সেগুলি কোনও আলাদা থ্রেডে নিষ্পত্তি করা হয় তবে আপনার একটি সিঙ্ক্রোনাইজেশন সমস্যা রয়েছে, এই পদ্ধতিতে এটি কোনও সমস্যা নয়।
লি

33

আমি আমার সমস্ত কোডে ফর্মটি ব্যবহার করছি।

private void DoGUISwitch()
{ 
    Invoke( ( MethodInvoker ) delegate {
        object1.Visible = true;
        object2.Visible = false;
    });
} 

আমি এটি এখানে ব্লগ এন্ট্রি উপর ভিত্তি করে করেছি । আমার এই পদ্ধতিটি আমাকে ব্যর্থ করে ফেলেনি, তাই InvokeRequiredসম্পত্তিটির চেক দিয়ে আমার কোড জটিল করার কোনও কারণ আমি দেখতে পাচ্ছি না ।

আশাকরি এটা সাহায্য করবে.


+1 - আপনি যে একই ব্লগ এন্ট্রি করেছেন তাতে আমি হোঁচট খেয়েছি এবং মনে হয় এটি কোনও প্রস্তাবিতের সবচেয়ে পরিষ্কার পদ্ধতির
টম বুশেল

3
এই পদ্ধতির ব্যবহার করে একটি ছোট্ট পারফরম্যান্স হিট হয়েছে, যা একাধিকবার ডেকে আনা যেতে পারে। stackoverflow.com/a/747218/724944
surfen

4
আপনি ব্যবহার করতে হবে InvokeRequiredআগে নিয়ন্ত্রণ দেখানো হয়ে থাকে তাহলে কোড সঞ্চালিত হতে পারে অথবা আপনি একটি মারাত্মক ব্যতিক্রম হবে না।
56ka

9

একটি থ্রেডস্যাফআইএনভোক.স্নিপেট ফাইল তৈরি করুন এবং তারপরে আপনি কেবল আপডেটের স্টেটমেন্টগুলি নির্বাচন করতে পারেন, ডান ক্লিক করুন এবং 'আশেপাশে ...' বা Ctrl-K + S নির্বাচন করতে পারেন:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>ThreadsafeInvoke</Title>
    <Shortcut></Shortcut>
    <Description>Wraps code in an anonymous method passed to Invoke for Thread safety.</Description>
    <SnippetTypes>
      <SnippetType>SurroundsWith</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="CSharp">
      <![CDATA[
      Invoke( (MethodInvoker) delegate
      {
          $selected$
      });      
      ]]>
    </Code>
  </Snippet>
</CodeSnippet>

6

এখানে লি, অলিভার এবং স্টিফেনের উত্তরগুলির একটি উন্নত / সংযুক্ত সংস্করণ রয়েছে।

public delegate void InvokeIfRequiredDelegate<T>(T obj)
    where T : ISynchronizeInvoke;

public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action)
    where T : ISynchronizeInvoke
{
    if (obj.InvokeRequired)
    {
        obj.Invoke(action, new object[] { obj });
    }
    else
    {
        action(obj);
    }
} 

টেম্পলেটটি নমনীয় এবং andালাই-কম কোডের জন্য মঞ্জুরি দেয় যা ডেডিকেটেড ডেলিগেট দক্ষতা সরবরাহ করার সময় অনেক বেশি পাঠযোগ্য।

progressBar1.InvokeIfRequired(o => 
{
    o.Style = ProgressBarStyle.Marquee;
    o.MarqueeAnimationSpeed = 40;
});

4

আমি প্রতিবার নতুন উদাহরণ তৈরি করার পরিবর্তে কোনও পদ্ধতি ডেলিগেটের একক উদাহরণ ব্যবহার করব। আমার ক্ষেত্রে আমি ব্যাকগ্রাউন্ড ওয়ার্কারের অগ্রগতি এবং (তথ্য / ত্রুটি) বার্তাগুলি একটি স্ক্যুয়াল উদাহরণ থেকে বড় ডেটা অনুলিপি এবং কাস্ট করে দেখাতাম। প্রায় 70000 অগ্রগতি এবং বার্তা কল হওয়ার পরেও আমার ফর্মটি কাজ করা এবং নতুন বার্তা প্রদর্শন বন্ধ করে দিয়েছে। যখন আমি একক বিশ্বব্যাপী উদাহরণ প্রতিনিধি ব্যবহার শুরু করি তখন এটি ঘটে না।

delegate void ShowMessageCallback(string message);

private void Form1_Load(object sender, EventArgs e)
{
    ShowMessageCallback showMessageDelegate = new ShowMessageCallback(ShowMessage);
}

private void ShowMessage(string message)
{
    if (this.InvokeRequired)
        this.Invoke(showMessageDelegate, message);
    else
        labelMessage.Text = message;           
}

void Message_OnMessage(object sender, Utilities.Message.MessageEventArgs e)
{
    ShowMessage(e.Message);
}

3

ব্যবহার:

control.InvokeIfRequired(c => c.Visible = false);

return control.InvokeIfRequired(c => {
    c.Visible = value

    return c.Visible;
});

কোড:

using System;
using System.ComponentModel;

namespace Extensions
{
    public static class SynchronizeInvokeExtensions
    {
        public static void InvokeIfRequired<T>(this T obj, Action<T> action)
            where T : ISynchronizeInvoke
        {
            if (obj.InvokeRequired)
            {
                obj.Invoke(action, new object[] { obj });
            }
            else
            {
                action(obj);
            }
        }

        public static TOut InvokeIfRequired<TIn, TOut>(this TIn obj, Func<TIn, TOut> func) 
            where TIn : ISynchronizeInvoke
        {
            return obj.InvokeRequired
                ? (TOut)obj.Invoke(func, new object[] { obj })
                : func(obj);
        }
    }
}

2

আমি এটিকে কিছুটা আলাদা করতে চাই, কোনও অ্যাকশনের প্রয়োজনে আমি "নিজেকে" কল করতে চাই,

    private void AddRowToListView(ScannerRow row, bool suspend)
    {
        if (IsFormClosing)
            return;

        if (this.InvokeRequired)
        {
            var A = new Action(() => AddRowToListView(row, suspend));
            this.Invoke(A);
            return;
        }
         //as of here the Code is thread-safe

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


-3

আপনার কখনই এমন কোড লেখা উচিত হবে না যা এর মতো দেখায়:

private void DoGUISwitch() {
    if (object1.InvokeRequired) {
        object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
    } else {
        object1.Visible = true;
        object2.Visible = false;
    }
}

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

রেফারেন্স: কন্ট্রোল.আবেদনের প্রয়োজনীয় সম্পত্তি যেখানে আপনি নিম্নলিখিতটি পড়তে পারেন:

ইনভোকরিওয়েড প্রোপার্টি ছাড়াও, কন্ট্রোলের চারটি পদ্ধতি রয়েছে যা কল করার জন্য থ্রেড নিরাপদ: যদি কন্ট্রোলের জন্য হ্যান্ডেলটি ইতিমধ্যে তৈরি করা হয়ে থাকে তবে ইনভোক, বিগেইনভোক, এন্ডআইভোভাক এবং ক্রিয়েট গ্রাফিক্স।

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


ওহে, আপনার উত্তরের জন্য ধন্যবাদ। আমি এই প্রশ্নটি জিজ্ঞাসা করে বহু বছর হয়ে গেছে (এবং আমি সি # এর সাথে কাজ করেছি ঠিক সেই দীর্ঘ সময় ধরে), তবে আমি ভাবছিলাম যে আপনি আরও কিছুটা ব্যাখ্যা করতে পারেন কিনা? আপনি যে ডক্স সংযুক্ত করেছেন invoke()সেগুলি নিয়ন্ত্রণের আগে একটি হ্যান্ডেল দেওয়ার আগে এটি কল করার একটি নির্দিষ্ট বিপদের উল্লেখ করে, তবে আইএমএইচও আপনার বর্ণিত বিবরণ বর্ণনা করে না। এই সমস্ত invoke()বাজে কথাগুলির পুরো বিষয়টি হ'ল থ্রেড-নিরাপদ উপায়ে ইউআই আপডেট করা এবং আমি কি মনে করব যে কোনও ব্লকিং প্রসঙ্গে আরও নির্দেশাবলী রাখলে তোতলাম্ব হয়? (উঃ ... খুশী আমি
এমটেক

আমি আরও লক্ষ করতে চাই যে মূল কোডটি ঘন ঘন ব্যবহার করার পরেও (যখন ফিরে) তখনও আপনি আমার দ্বৈত-সিপিইউ ডেস্কটপে আপনি যে সমস্যাটি বর্ণনা করেছেন তা আমি পর্যবেক্ষণ করিনি
টম কোরিলিস

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