इस समस्या को समझाने के लिए मैंने सबकुछ एक छोटे नमूना अनुप्रयोग में जरूरी रखा जो उम्मीद है कि समस्या बताती है। मैंने वास्तव में जितनी कम संभव लाइनों में सबकुछ धक्का देने की कोशिश की, लेकिन मेरे असली आवेदन में ये अलग-अलग कलाकार एक-दूसरे को नहीं जानते और यह भी नहीं करना चाहिए। तो, सरल उत्तर "चर को कुछ पंक्तियों को ऊपर ले जाएं और उस पर आमंत्रित करें" काम नहीं करेगा।बाइंडिंगसोर्स और क्रॉस-थ्रेड अपवाद
तो आइए कोड के साथ शुरू करें और बाद में थोड़ा और स्पष्टीकरण दें। सबसे पहले एक साधारण वर्ग है जो INotifyProperty लागू करता है:
public class MyData : INotifyPropertyChanged
{
private string _MyText;
public MyData()
{
_MyText = "Initial";
}
public string MyText
{
get { return _MyText; }
set
{
_MyText = value;
PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
तो कुछ खास नहीं है। और यहाँ उदाहरण कोड जो केवल किसी भी खाली सांत्वना आवेदन परियोजना में रखा जा सकता है:
static void Main(string[] args)
{
// Initialize the data and bindingSource
var myData = new MyData();
var bindingSource = new BindingSource();
bindingSource.DataSource = myData;
// Initialize the form and the controls of it ...
var form = new Form();
// ... the TextBox including data bind to it
var textBox = new TextBox();
textBox.DataBindings.Add("Text", bindingSource, "MyText");
textBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
textBox.Dock = DockStyle.Top;
form.Controls.Add(textBox);
// ... the button and what happens on a click
var button = new Button();
button.Text = "Click me";
button.Dock = DockStyle.Top;
form.Controls.Add(button);
button.Click += (_, __) =>
{
// Create another thread that does something with the data object
var worker = new BackgroundWorker();
worker.RunWorkerCompleted += (___, ____) => button.Enabled = true;
worker.DoWork += (___, _____) =>
{
for (int i = 0; i < 10; i++)
{
// This leads to a cross-thread exception
// but all i'm doing is simply act on a property in
// my data and i can't see here that any gui is involved.
myData.MyText = "Try " + i;
}
};
button.Enabled = false;
worker.RunWorkerAsync();
};
form.ShowDialog();
}
आप इस कोड को चलाने के हैं, तो आप MyText
संपत्ति को बदलने के लिए कोशिश कर रहा द्वारा एक क्रॉस-धागा अपवाद मिलेगा। यह आता है, MyData
ऑब्जेक्ट PropertyChanged
पर कॉल करता है जिसे BindindSource
द्वारा पकड़ा जाएगा। यह Binding
के अनुसार, TextBox
की संपत्ति को अपडेट करने का प्रयास करेगा। जो स्पष्ट रूप से अपवाद की ओर जाता है।
मेरे सबसे बड़ी समस्या यहां तथ्य यह है कि MyData
वस्तु एक जीयूआई बारे में कुछ पता नहीं करना चाहिए (कारण यह एक सरल डेटा वस्तु है) से आता है। इसके अलावा कार्यकर्ता थ्रेड को गुई के बारे में कुछ नहीं पता है। यह बस डेटा ऑब्जेक्ट्स के समूह पर कार्य करता है और उन्हें कुशल बनाता है।
आईएमएचओ मुझे लगता है कि BindingSource
को यह पता होना चाहिए कि प्राप्त करने वाला ऑब्जेक्ट कौन सा थ्रेड रहता है और मूल्य प्राप्त करने के लिए Invoke()
एप्राइपियेट करें। दुर्भाग्यवश यह इस में निर्मित नहीं है (या मैं गलत हूं?), इसलिए मेरा प्रश्न है:
डेटा क्रॉस-थ्रेड अपवाद को कैसे हल किया जा सकता है यदि डेटा ऑब्जेक्ट और न ही वर्कर थ्रेड को बाध्यकारी स्रोत के बारे में कुछ पता है जो सुन रहा है उनके कार्यक्रमों के लिए डेटा को एक गुई में धक्का देना।
इस्तेमाल किया लेकिन समस्या यह है कि मैं 'MyData' वर्ग के भीतर यूआई धागा नहीं जानता है। तो यूआई थ्रेड का आह्वान कैसे करें यदि मेरे पास उस पर किसी भी नियंत्रण तक पहुंच नहीं है जो वर्तमान में 'Invoke()' को कॉल करने के लिए फॉर्म पर है? – Oliver
@ ओलिवर: अरे आपने इस मुद्दे को हल किया है? मैं इस तरह से कुछ भी अटक गया हूँ? –
@ माहेश: इस सवाल का अपना जवाब जोड़ें, मैंने इसे कैसे हल किया। यह सही नहीं है, लेकिन कुछ भी नहीं है। – Oliver