问题
So I'm working on my first multithreaded WPF app. Please bear in mind I have little to no understanding of how to implement multithreading - I've done it in a few apps and always work off the existing code. This is my first attempt at it in WPF which is apparently quite different to Windows Forms...
So basically I'm working on this example which oddly enough doesn't mention that you have to instantiate a new thread and start it - I guess the author felt that was self evident even to newbies like myself.
In any case, it works okay until I get to the point where I want to update the properties of my UI controls at which point I'm hit with an InvalidOperationException
that says the calling thread can't access the control because the control belongs to a different thread
So basically this is not a thread safe way to work, but I'm at a loss as to how I should fix this...
Here's my code:
string fn = "";
private void btnBrowse_Click(object sender, RoutedEventArgs e)
{
if (lblActivity.Visibility != System.Windows.Visibility.Hidden)
{
lblActivity.Visibility = System.Windows.Visibility.Hidden;
}
if (lstResult.Items.Count != 0)
{
lstResult.Items.Clear();
}
OpenFileDialog ofd = new OpenFileDialog();
Nullable<bool> result = ofd.ShowDialog();
if (result == true)
{
txtSource.Text = ofd.FileName;
txtDest.Text = ofd.FileName;
fn = ofd.SafeFileName;
PopulateControlsDuingLongRefreshCall("read");
}
}
private void PopulateControlsDuingLongRefreshCall(string action)
{
ShowProcessing();
ThreadStart ts = delegate
{
switch (action)
{
case "format":
Populate();
CleanData();
break;
case "read":
TextReader tr = new StreamReader(txtSource.Text);
txtPreview.Text = tr.ReadToEnd();
break;
}
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (EventHandler)delegate
{
HideProcessing();
}, null, null);
};
Thread thr = new Thread(ts);
thr.Start();
}
private void ShowProcessing()
{
recProcessing.Visibility = Visibility.Visible;
}
private void HideProcessing()
{
recProcessing.Visibility = Visibility.Collapsed;
}
If anyone can suggest a solution here or explain more about the concept I'm using (I'm still pretty fuzzy on it) so that I can understand enough to find a solution on my own, that'd be much appreciated.
Thanks in advance!
EDIT
The error also comes up if I'm getting the UI control properties TextReader tr = new StreamReader(txtSource.Text);
also throws the exception.
回答1:
In your delegate, rather than access txtSource directly, try using the following function to return a streamreader:
private StreamReader GetTxtSource()
{
if (!this.Dispatcher.CheckAccess())
{
return this.Dispatcher.Invoke(new Func<StreamReader>(this.GetTxtSource)) as StreamReader;
}
return new StreamReader(txtSource.Text);
}
You might need to use txtSource.Dispatcher.CheckAccess() instead.
回答2:
What you really need to understand here, is that you CANNOT access any control from another thread than the UI thread.
So when you're doing
case "read":
TextReader tr = new StreamReader(txtSource.Text);
txtPreview.Text = tr.ReadToEnd();
break;
you're trying to set the value of a Textbox (txtPreview), in the background thread.
What you need to do, is to read the file content in the background thread, and then use the UI thread to update the textbox value, by using the Dispatcher:
case "read":
TextReader tr = new StreamReader(txtSource.Text);
string content = tr.ReadToEnd();
Dispatcher.Invoke((Action)(() =>
{
txtPreview.Text = content;
}));
txtPreview.Text = tr.ReadToEnd();
break;
来源:https://stackoverflow.com/questions/14773183/invalidoperationexception-when-multithreading-in-wpf