কলিং থ্রেড এই বিষয়টিকে অ্যাক্সেস করতে পারে না কারণ একটি ভিন্ন থ্রেড এটির মালিক


341

আমার কোডটি নীচের মতো

public CountryStandards()
{
    InitializeComponent();
    try
    {
        FillPageControls();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Country Standards", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

/// <summary>
/// Fills the page controls.
/// </summary>
private void FillPageControls()
{
    popUpProgressBar.IsOpen = true;
    lblProgress.Content = "Loading. Please wait...";
    progress.IsIndeterminate = true;
    worker = new BackgroundWorker();
    worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
    worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged);
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;
    worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();                    
}

private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    GetGridData(null, 0); // filling grid
}

private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    progress.Value = e.ProgressPercentage;
}

private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    worker = null;
    popUpProgressBar.IsOpen = false;
    //filling Region dropdown
    Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT_REGION";
    DataSet dsRegionStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsRegionStandards, 0))
        StandardsDefault.FillComboBox(cmbRegion, dsRegionStandards.Tables[0], "Region", "RegionId");

    //filling Currency dropdown
    objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT_CURRENCY";
    DataSet dsCurrencyStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsCurrencyStandards, 0))
        StandardsDefault.FillComboBox(cmbCurrency, dsCurrencyStandards.Tables[0], "CurrencyName", "CurrencyId");

    if (Users.UserRole != "Admin")
        btnSave.IsEnabled = false;

}

/// <summary>
/// Gets the grid data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="pageIndex">Index of the page.( used in case of paging)   </pamam>
private void GetGridData(object sender, int pageIndex)
{
    Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT";
    objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;
    DataSet dsCountryStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsCountryStandards, 0) && (chkbxMarketsSearch.IsChecked == true || chkbxBudgetsSearch.IsChecked == true || chkbxProgramsSearch.IsChecked == true))
    {
        DataTable objDataTable = StandardsDefault.FilterDatatableForModules(dsCountryStandards.Tables[0], "Country", chkbxMarketsSearch, chkbxBudgetsSearch, chkbxProgramsSearch);
        dgCountryList.ItemsSource = objDataTable.DefaultView;
    }
    else
    {
        MessageBox.Show("No Records Found", "Country Standards", MessageBoxButton.OK, MessageBoxImage.Information);
        btnClear_Click(null, null);
    }
}

objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;গ্রিড ডেটা পাওয়ার পদক্ষেপটি ব্যতিক্রম ছুঁড়ে

কলিং থ্রেড এই বিষয়টিকে অ্যাক্সেস করতে পারে না কারণ একটি ভিন্ন থ্রেড এটির মালিক।

এখানে কি সমস্যা?


উত্তর:


698

এটি শুরু করার সাথে লোকেদের একটি সাধারণ সমস্যা। যখনই আপনি মূল থ্রেড বাদে অন্য থ্রেড থেকে আপনার ইউআই উপাদানগুলি আপডেট করেন, আপনাকে ব্যবহার করতে হবে:

this.Dispatcher.Invoke(() =>
{
    ...// your code here.
});

control.Dispatcher.CheckAccess()বর্তমান থ্রেড নিয়ন্ত্রণের মালিক কিনা তা পরীক্ষা করতে আপনিও ব্যবহার করতে পারেন । যদি এটির মালিকানা থাকে তবে আপনার কোডটি সাধারণ দেখায়। অন্যথায়, উপরের প্যাটার্নটি ব্যবহার করুন।


3
আমার ওপি'র মতো একই সমস্যা; আমার এখন সমস্যা হ'ল ইভেন্টটি এখন স্ট্যাকের ওভারফ্লো করেছে। : \
মালাভোস

2
আমার পুরানো প্রকল্পে ফিরে এসে এটিকে সমাধান করেছি। এছাড়াও, আমি এটি +1 করতে ভুলে গিয়েছিলাম। এই পদ্ধতিটি বেশ ভাল কাজ করে! এটি কেবলমাত্র আমাদের স্থানীয়করণের সংস্থানগুলি লোড করতে থ্রেড ব্যবহার করে 10 সেকেন্ডে বা তারও বেশি সময়ে আমার অ্যাপ্লিকেশন লোডিংয়ের সময় উন্নত করে। চিয়ার্স!
মালাভোস

4
আমি যদি ভুল না করি তবে আপনি কোনও অ-মালিকের থ্রেড থেকে কোনও UI অবজেক্টটিও পড়তে পারবেন না; আমাকে কিছুটা অবাক করে দিলেন।
এলিয়ট

32
Application.Current.Dispatcher.Invoke(MyMethod, DispatcherPriority.ContextIdle);এই উত্তর
জাম্পিংজেজ্জা

2
+1 টি। হা! জিনিসগুলি decoupled রাখতে আমি কিছু ডাব্লুপিএফ হ্যাকারির জন্য এটি ব্যবহার করেছি। আমি একটি স্থিতিশীল প্রসঙ্গে ছিলাম তাই আমি this.Dispatcher.Invokeপরিবর্তে ব্যবহার করতে পারি না .... myControl.Dispatcher.Invoke:) আমার কোনও বস্তুটি ফেরত দেওয়া দরকার ছিল তাই করেছি myControlDispatcher.Invoke<object>(() => myControl.DataContext);
সি তেওয়াল্ট

52

এর জন্য আরও একটি ভাল ব্যবহার Dispatcher.Invokeহ'ল অন্য কাজগুলি সম্পাদন করে এমন একটি ফাংশনে অবিলম্বে ইউআই আপডেট করার জন্য:

// Force WPF to render UI changes immediately with this magic line of code...
Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);

আমি এটি " প্রসেসিং ... " বোতামের পাঠ্য আপডেট করতে এবং তৈরি করার সময় এটি অক্ষম করতে ব্যবহার করিWebClient অনুরোধ করার ।


4
এই উত্তরটি মেটা নিয়ে আলোচনা করা হচ্ছে। meta.stackoverflow.com/questions/361844/…
এখনও মনিকা

এটি কি ইন্টারনেট থেকে ডেটা পেতে আমার নিয়ন্ত্রণ বন্ধ করে দিয়েছে?
ওয়াসিম আহমেদ না

41

আমার 2 সেন্ট যোগ করার জন্য, আপনি যদি আপনার কোডটি কল করেও ব্যতিক্রম ঘটতে পারে System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()
বিন্দু আপনাকে কল করার আছে যে Invoke()এর Dispatcherএর নিয়ন্ত্রণ যা আপনি অ্যাক্সেস করার চেষ্টা করছেন , যা কিছু কিছু ক্ষেত্রে যেমন একই হতে পারেSystem.Windows.Threading.Dispatcher.CurrentDispatcher । সুতরাং পরিবর্তে আপনার ব্যবহার করা উচিতYourControl.Dispatcher.Invoke() নিরাপদ । আমি বুঝতে পারার কয়েক ঘন্টা আগে আমার মাথাটি বেধে ছিল।

হালনাগাদ

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


4
@ l33t: ডাব্লুপিএফ একটি অ্যাপ্লিকেশনটিতে একাধিক ইউআই থ্রেড সমর্থন করে, যার প্রত্যেকটির নিজস্ব নিজস্ব Dispatcher। এই ক্ষেত্রে (যা স্বীকার করা বিরল), কল Control.Dispatcherকরা নিরাপদ পদ্ধতি। রেফারেন্সের জন্য আপনি এই নিবন্ধটি পাশাপাশি এই এসও পোস্ট দেখতে পাবেন (বিশেষত স্কুইডওয়ার্ডের উত্তর)।
ডটনেট

1
মজার বিষয় হল, আমি যখন এই পৃষ্ঠায় গুগল করেছিলাম এবং নামছিলাম এবং আমাদের বেশিরভাগের মতো সর্বাধিক ভোট দেওয়া উত্তরটি চেষ্টা করেছিলাম, যা আমার সমস্যাটির সমাধান করে নি তখন আমি এই ব্যতিক্রমটির মুখোমুখি হয়েছি। আমি তখন এই কারণটি খুঁজে পেয়েছি এবং এটি পিয়ার বিকাশকারীদের জন্য এখানে পোস্ট করেছি।
dotNET

1
@ l33t, আপনি যদি এমভিভিএম সঠিকভাবে ব্যবহার করে থাকেন তবে সমস্যাটি হওয়া উচিত নয়। ভিউমোডেলস এবং মডেলগুলি নিয়ন্ত্রণের কিছুই জানে না এবং নিয়ন্ত্রণগুলি জানার প্রয়োজন নেই, তবে ভিউটি মোডেলস এবং মডেলগুলি এটি কীভাবে ডিসপ্যাচার ব্যবহার করছে তা জেনে রাখা উচিত।
অ্যারোনবুরো

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

1
ডাব্লুপিএফ বাইন্ডিং ইঞ্জিন স্বয়ংক্রিয়ভাবে সম্পত্তিটিকে সঠিক ডিসপ্যাচারে পরিবর্তন করে। এই কারণেই ডিসিপাচার সম্পর্কে ভিএমের কোনও প্রয়োজন নেই; এটি যা করতে হবে তা কেবল সম্পত্তি পরিবর্তিত ইভেন্টগুলি বাড়ানো। উইনফর্মস বাইন্ডিং একটি আলাদা গল্প।
অ্যারোনবুরো

34

আপনি এ সমস্যার সম্মুখীন এবং UI নিয়ন্ত্রণ একটি তে তৈরি ছিল পৃথক কর্মী যখন সঙ্গে কাজ থ্রেড BitmapSourceবা ImageSourceWPF, কল Freeze()প্রথম ক্ষণস্থায়ী আগে পদ্ধতি BitmapSourceবা ImageSourceকোন পদ্ধতি করার জন্য একটি প্যারামিটার হিসাবে। ব্যবহার করা Application.Current.Dispatcher.Invoke()যেমন উদাহরণস্বরূপ কাজ করে না


24
আহা, কেউ বোঝে না এমন কিছু সমাধান করার জন্য একটি ভাল পুরানো অস্পষ্ট এবং রহস্যজনক কৌশল nothing
এডউইন

2
আমি কেন এটি কাজ করে এবং কীভাবে আমি নিজে এটি আবিষ্কার করতে পারতাম সে সম্পর্কে আরও তথ্য চাই।
জাভিয়ের শায়


25

আমার সাথে এটি ঘটেছে কারণ আমি এটির access UIমধ্যে অংশ দেওয়ার চেষ্টা করেছিanother thread insted of UI thread

এটার মত

private void button_Click(object sender, RoutedEventArgs e)
{
    new Thread(SyncProcces).Start();
}

private void SyncProcces()
{
    string val1 = null, val2 = null;
    //here is the problem 
    val1 = textBox1.Text;//access UI in another thread
    val2 = textBox2.Text;//access UI in another thread
    localStore = new LocalStore(val1);
    remoteStore = new RemoteStore(val2);
}

এই সমস্যাটি সমাধান করার জন্য, ক্যান্ডাইড তার উত্তরে উপরে উল্লিখিত কিসের ভিতরে কোনও ইউআই কল মোড়ক করুন

private void SyncProcces()
{
    string val1 = null, val2 = null;
    this.Dispatcher.Invoke((Action)(() =>
    {//this refer to form in WPF application 
        val1 = textBox.Text;
        val2 = textBox_Copy.Text;
    }));
    localStore = new LocalStore(val1);
    remoteStore = new RemoteStore(val2 );
}

1
সম্মত, কারণ এই হল না সদৃশ উত্তর বা plagiaristic, কিন্তু এটা পরিবর্তে অন্য উত্তর, উদাসীন ছিল যখন কি আগের পোস্ট করা হয়েছে জন্য ক্রেডিট দান একটি ভাল উদাহরণ প্রদান করে।
Panzercrisis

আপভোটটি একটি সুস্পষ্ট উত্তরের জন্য। যদিও এটি অন্যদের দ্বারা লেখা হয়েছিল, তবে এটি যে আটকে আছে তার পক্ষে এটি স্পষ্ট হয়ে যায়।
নিশান্টএম

15

কোনও কারণে ক্যান্ডাইডের উত্তর তৈরি হয়নি। এটি সহায়ক ছিল, যদিও এটি আমাকে এটি খুঁজে বের করতে পরিচালিত করেছিল, যা নিখুঁতভাবে কাজ করেছিল:

System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
   //your code here...
}));

এটা সম্ভব যে আপনি ফর্মের ক্লাস থেকে কল করেননি। হয় আপনি উইন্ডোতে একটি রেফারেন্স দখল করতে পারেন, বা আপনি সম্ভবত যা পরামর্শ দিয়েছেন ব্যবহার করতে পারেন।
সিমোন

4
যদি এটি আপনার পক্ষে কাজ করে তবে এটি প্রথমে ব্যবহার করা অপ্রয়োজনীয় ছিল। System.Windows.Threading.Dispatcher.CurrentDispatcherহয় বর্তমান থ্রেড জন্য ডেস্প্যাচার । এর অর্থ আপনি যদি কোনও পটভূমি থ্রেডে থাকেন তবে এটি ইউআই থ্রেডের প্রেরণকারী হতে চলেছে না । ইউআই থ্রেডের প্রেরণকারী অ্যাক্সেস করতে, ব্যবহার করুন System.Windows.Application.Current.Dispatcher

13

আপনাকে ইউআইতে আপডেট করতে হবে, সুতরাং ব্যবহার করুন

Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)})); 

4

এটি আমার পক্ষে কাজ করে।

new Thread(() =>
        {

        Thread.CurrentThread.IsBackground = false;
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate {

          //Your Code here.

        }, null);
        }).Start();

3

আমি এটিও পেয়েছি যে System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()ডটনেট তার উত্তরে যেমন লিখেছিল ঠিক তেমন লক্ষ্য নিয়ন্ত্রণ প্রেরণকারী হয় না। নিয়ন্ত্রণের নিজস্ব প্রেরণকারীর কাছে আমার অ্যাক্সেস ছিল না, তাই আমি ব্যবহার করেছি Application.Current.Dispatcherএবং এটি সমস্যার সমাধান করেছে।


2

সমস্যাটি হচ্ছে আপনি কল করছেন GetGridData একটি পটভূমি থ্রেড থেকে । এই পদ্ধতিটি বেশ কয়েকটি ডাব্লুপিএফ নিয়ন্ত্রণগুলি অ্যাক্সেস করে যা মূল থ্রেডের সাথে আবদ্ধ। একটি পটভূমি থ্রেড থেকে তাদের অ্যাক্সেসের যে কোনও প্রচেষ্টা এই ত্রুটির দিকে পরিচালিত করবে।

সঠিক থ্রেড ফিরে পেতে যাতে আপনার ব্যবহার করা উচিত SynchronizationContext.Current.Post। তবে এই বিশেষ ক্ষেত্রে মনে হচ্ছে আপনি করছেন বেশিরভাগ কাজটি ইউআই ভিত্তিক। সুতরাং আপনি কেবল ইউআই থ্রেডে ফিরে যেতে এবং কিছু কাজ করার জন্য একটি পটভূমি থ্রেড তৈরি করবেন। আপনাকে আপনার কোডটি কিছুটা রিফ্যাক্টর করতে হবে যাতে এটি ব্যাকগ্রাউন্ড থ্রেডে ব্যয়বহুল কাজ করতে পারে এবং তারপরে ইউআই থ্রেডে নতুন ডেটা পোস্ট করতে পারে


2

এখানে উল্লিখিত হিসাবে , Dispatcher.Invokeইউআই স্থির করতে পারে। Dispatcher.BeginInvokeপরিবর্তে ব্যবহার করা উচিত।

চেকিং এবং কল পাঠানোর অনুরোধকে সহজ করার জন্য এখানে একটি সহজ এক্সটেনশন ক্লাস।

নমুনা ব্যবহার: (ডাব্লুপিএফ উইন্ডো থেকে কল)

this Dispatcher.InvokeIfRequired(new Action(() =>
{
    logTextbox.AppendText(message);
    logTextbox.ScrollToEnd();
}));

সম্প্রসারণ শ্রেণি:

using System;
using System.Windows.Threading;

namespace WpfUtility
{
    public static class DispatcherExtension
    {
        public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
        {
            if (dispatcher == null)
            {
                return;
            }
            if (!dispatcher.CheckAccess())
            {
                dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
                return;
            }
            action();
        }
    }
}

0

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


0

আমি আমার ডাব্লুপিএফ অ্যাপ্লিকেশনটিতে ক্যাসকেডিং কম্বোবক্সগুলি যুক্ত করার সময় ত্রুটিটি পেয়েছি এবং এই API টি ব্যবহার করে ত্রুটিটি সমাধান করেছি:

    using System.Windows.Data;

    private readonly object _lock = new object();
    private CustomObservableCollection<string> _myUiBoundProperty;
    public CustomObservableCollection<string> MyUiBoundProperty
    {
        get { return _myUiBoundProperty; }
        set
        {
            if (value == _myUiBoundProperty) return;
            _myUiBoundProperty = value;
            NotifyPropertyChanged(nameof(MyUiBoundProperty));
        }
    }

    public MyViewModelCtor(INavigationService navigationService) 
    {
       // Other code...
       BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock );

    }

বিশদগুলির জন্য, দয়া করে https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindOperations.Enable CollectionsSynchronization) ;k(TargetFrameworkMoniker- .NETFramework. % 3Dv4.7); ট (DevLang-csharp) & য় সত্য =

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