ডাব্লুপিএফ-তে নিরাপদে ইউআই (মেইন) থ্রেড অ্যাক্সেস করা হচ্ছে


99

আমার কাছে একটি অ্যাপ্লিকেশন রয়েছে যা প্রতিবার আমার ডেটাগ্রিডকে আপডেট করে যা আমি দেখছি যে লগ ফাইলটি নীচের পদ্ধতিতে আপডেট হয় (নতুন পাঠ্যের সাথে সংযুক্ত):

private void DGAddRow(string name, FunctionType ft)
    {
                ASCIIEncoding ascii = new ASCIIEncoding();

    CommDGDataSource ds = new CommDGDataSource();

    int position = 0;
    string[] data_split = ft.Data.Split(' ');
    foreach (AttributeType at in ft.Types)
    {
        if (at.IsAddress)
        {

            ds.Source = HexString2Ascii(data_split[position]);
            ds.Destination = HexString2Ascii(data_split[position+1]);
            break;
        }
        else
        {
            position += at.Size;
        }
    }
    ds.Protocol = name;
    ds.Number = rowCount;
    ds.Data = ft.Data;
    ds.Time = ft.Time;

    dataGridRows.Add(ds); 

    rowCount++;
    }
    ...
    private void FileSystemWatcher()
    {
        FileSystemWatcher watcher = new FileSystemWatcher(Environment.CurrentDirectory);
        watcher.Filter = syslogPath;
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
            | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        watcher.Changed += new FileSystemEventHandler(watcher_Changed);
        watcher.EnableRaisingEvents = true;
    }

    private void watcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (File.Exists(syslogPath))
        {
            string line = GetLine(syslogPath,currentLine);
            foreach (CommRuleParser crp in crpList)
            {
                FunctionType ft = new FunctionType();
                if (crp.ParseLine(line, out ft))
                {
                    DGAddRow(crp.Protocol, ft);
                }
            }
            currentLine++;
        }
        else
            MessageBox.Show(UIConstant.COMM_SYSLOG_NON_EXIST_WARNING);
    }

ইভেন্টটি যখন ফাইলওয়াচারের জন্য উত্থাপিত হয়, কারণ এটি একটি পৃথক থ্রেড তৈরি করে, যখন আমি ডেটাগ্রিডআরও চালানোর চেষ্টা করি। অ্যাড (ডিএস); নতুন সারিটি যুক্ত করতে, প্রোগ্রামটি ডিবাগ মোডের সময় দেওয়া কোনও সতর্কতা ছাড়াই ক্র্যাশ হয়ে যায়।

উইনফর্মগুলিতে, ইনভোক ফাংশনটি ব্যবহার করে এটি সহজেই সমাধান করা হয়েছিল তবে ডাব্লুপিএফ-এ কীভাবে যাবেন আমি নিশ্চিত নই।

উত্তর:


204

তুমি ব্যবহার করতে পার

Dispatcher.Invoke(Delegate, object[])

উপর Application'গুলি (বা কোনো UIElement' গুলি) ডেস্প্যাচার।

আপনি এটির উদাহরণস্বরূপ এটি ব্যবহার করতে পারেন:

Application.Current.Dispatcher.Invoke(new Action(() => { /* Your code here */ }));

বা

someControl.Dispatcher.Invoke(new Action(() => { /* Your code here */ }));

উপরের পদ্ধতিটি একটি ত্রুটি দিচ্ছিল কারণ লাইনটি চালানোর সময় অ্যাপ্লিকেশন C বর্তমানটি শূন্য। কেন এমন হবে?
l46kok

আপনি কেবল তার জন্য যে কোনও ইউআইইলেমেন্ট ব্যবহার করতে পারেন, যেহেতু প্রতিটি ইউআইইলেটের "ডিসপ্যাচার" সম্পত্তি রয়েছে।
ওল্ফগ্যাং জিগলারের

4
@ l46kok এর বিভিন্ন কারণ থাকতে পারে (কনসোল অ্যাপ্লিকেশন, উইনফর্মগুলি থেকে হোস্টিং ইত্যাদি)। @ ওল্ফগ্যাংজিজেলার যেমন বলেছিলেন, আপনি এর জন্য যে কোনও ইউআইইলেট ব্যবহার করতে পারেন। আমার Application.Currentকাছে এটি পরিষ্কার পরিচ্ছন্ন বলে আমি সাধারণত এটি ব্যবহার করি।
Botz3000

@ বটজ ৩০০০ আমার মনে হয় আমার এখানেও রেসের শর্তগুলির কিছু সমস্যা রয়েছে। উপরের প্রদত্ত কোডটি সংযোজন করার পরে, আমি যখন ডিবাগ মোডে যাই এবং ম্যানুয়ালি স্টেপওভারগুলি করি তখন কোডটি পুরোপুরি কাজ করে তবে আমি ডিবাগ ছাড়াই অ্যাপ্লিকেশনটি চালানোর সময় কোডটি ক্র্যাশ হয়ে যায়। আমি নিশ্চিত না যে এখানে কীভাবে লক করব যা সমস্যার সৃষ্টি করছে।
l46kok

4
@ l46kok আপনি যদি মনে করেন এটি একটি অচলাবস্থা, আপনি কল করতেও পারেন Dispatcher.BeginInvoke। এই পদ্ধতিটি ফাঁসির জন্য প্রতিনিধিদের সারি করে।
Botz3000

52

এটির সবচেয়ে ভাল উপায় SynchronizationContextহ'ল ইউআই থ্রেড থেকে একটি পেয়ে এটি ব্যবহার করা। এই শ্রেণিটি অন্য থ্রেডগুলিতে মার্শালিং কলগুলি বিমূর্ত করে এবং পরীক্ষাকে সহজ করে তোলে (ডাব্লুপিএফের Dispatcherসরাসরি ব্যবহারের বিপরীতে )। উদাহরণ স্বরূপ:

class MyViewModel
{
    private readonly SynchronizationContext _syncContext;

    public MyViewModel()
    {
        // we assume this ctor is called from the UI thread!
        _syncContext = SynchronizationContext.Current;
    }

    // ...

    private void watcher_Changed(object sender, FileSystemEventArgs e)
    {
         _syncContext.Post(o => DGAddRow(crp.Protocol, ft), null);
    }
}

অনেক ধন্যবাদ! গ্রহণযোগ্য সমাধানটি যতবার ডাকা হত ততক্ষণ ঝুলতে শুরু করে, তবে এটি কাজ করে।
ডভ

ভিউ মডেলযুক্ত কোনও অ্যাসেমব্লির কাছ থেকে আহ্বান করা হলেও এটি কাজ করে তবে কোনও "আসল" ডাব্লুপিএফ নয়, অর্থাত্ কোনও শ্রেণির পাঠাগার নেই is
ওনুর

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

আমি প্রথমে বুঝতে পারি নি, তবে এটি আমার পক্ষে কাজ করেছে .. খুব সুন্দর। (ডিজিএডিডিআরও একটি ব্যক্তিগত পদ্ধতি হিসাবে চিহ্নিত করা উচিত)
টিম ডেভিস

5

অন্য থ্রেড থেকে বা ব্যাকগ্রাউন্ড থেকে ইউআই পরিবর্তন করতে [ডিসপ্যাচার.আনভোক (ডিসপ্যাচারপ্রাইরিটি, ডেলিগেট)] ব্যবহার করুন ।

পদক্ষেপ 1 । নিম্নলিখিত নেমস্পেস ব্যবহার করুন

using System.Windows;
using System.Threading;
using System.Windows.Threading;

পদক্ষেপ 2 । নিম্নলিখিত লাইনটি রাখুন যেখানে আপনাকে ইউআই আপডেট করতে হবে

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
{
    //Update UI here
}));

বাক্য গঠন

[BrowsableAttribute(false)]
public object Invoke(
  DispatcherPriority priority,
  Delegate method
)

পরামিতি

priority

প্রকার: System.Windows.Threading.DispatcherPriority

অগ্রাধিকার, ডিসপ্যাচার ইভেন্টের সারিতে থাকা অন্যান্য অপেক্ষারত ক্রিয়াকলাপের সাথে সম্পর্কিত, নির্দিষ্ট পদ্ধতিটি চাওয়া হয়।

method

প্রকার: System.Delegate

এমন কোনও পদ্ধতির প্রতিনিধি যা কোনও আর্গুমেন্ট নেয় না, যা ডিসপ্যাচার ইভেন্টের কাতারে চাপানো হয়।

ফেরত মূল্য

প্রকার: System.Object

ডেলিগেটের কাছ থেকে ফেরতের মূল্য চাওয়া হয় বা বাতিল হয় যদি প্রতিনিধিটির কোনও ফেরতের মান থাকে না।

সংস্করণ সংক্রান্ত তথ্য

.NET ফ্রেমওয়ার্ক 3.0 থেকে উপলব্ধ

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