I'm trying to create parallel execution of a function in wpf c# which also runs actions on the UI. But when running there is always an exception at methods on UI Controls: The calling thread cannot access this object because a different thread owns it. The exception is always called on the second instance of the loop being run, so it isn't possible to manipulate the UI in two parallel running instances?
Is it possible to acces the UI in parallel?
Code:
do
{
if (listBox_Copy.SelectedIndex < listBox_Copy.Items.Count - 1)
{
listBox_Copy.SelectedIndex = listBox_Copy.SelectedIndex + 1;
listBox_Copy.ScrollIntoView(listBox_Copy.SelectedItem);
}
listBox_Copy.Focus();
huidigitem = listBox_Copy.SelectedItem as ListBoxItem;
currentitemindex = listBox_Copy.SelectedIndex;
currentitem = listBox_Copy.ItemContainerGenerator.ContainerFromIndex(currentitemindex) as ListBoxItem;
itemgrid = FindVisualChild<Grid>(currentitem);
senderbutton = (Button)sender;
Button playcues = itemgrid.FindName("Playbutton") as Button;
cuetrigger = itemgrid.FindName("cuetrigger") as TextBlock;
Jobs.Add(playcues);
} while (cuetrigger.Text != "go");
Parallel.ForEach(Jobs, playcues => { play(playcues, new RoutedEventArgs()); });
And then it crashes at the play function
private void play(object sender, System.Windows.RoutedEventArgs e)
{
Grid itemgrid = VisualTreeHelperExtensions.FindAncestor<Grid>(playcue);
...
}
It is not possible to access the UI from a background thread, all your updates must be on the main thread. You can do this by using the Dispatcher
Something like this
Action x = (Action)delegate {
//do my UI updating
};
Dispatcher.Invoke(x, new object[] { });
The trick is to use an IProgress<T> to report updates to the main thread. The IProgress<T> constructor accepts an anonymous function that will be run in the main thread and can thus update the UI.
Quoting from https://blog.stephencleary.com/2012/02/reporting-progress-from-async-tasks.html :
public async void StartProcessingButton_Click(object sender, EventArgs e)
{
// The Progress<T> constructor captures our UI context,
// so the lambda will be run on the UI thread.
var progress = new Progress<int>(percent =>
{
textBox1.Text = percent + "%";
});
// DoProcessing is run on the thread pool.
await Task.Run(() => DoProcessing(progress));
textBox1.Text = "Done!";
}
public void DoProcessing(IProgress<int> progress)
{
for (int i = 0; i != 100; ++i)
{
Thread.Sleep(100); // CPU-bound work
if (progress != null)
progress.Report(i);
}
}
Now, a little bit of self-promotion :) I created an IEnumerable<T> extension to run a parallel for with event callbacks that can directly modify the UI. You can have a look at it here:
https://github.com/jotaelesalinas/csharp-forallp
Hope it helps!
Related
I am trying to add threading into my program such that I don't freeze the entire main UI thread while doing "expensive" computational work.
Currently, my program runs an async Task pointing to a function named startWork() when a button is pressed like so:
async void startParse_Click(object sender, EventArgs e)
{
await Task.Run(() => startWork());
}
Normally for setting values I do the following:
niceButton.BeginInvoke(new MethodInvoker(() =>
{
niceButton.Text = "new text";
}));
However, for grabbing data from controls and using that data outside of the MethodInvoker, I'm having a bit of trouble. My goal is execute a foreach loop around my listView1.Items, outside of the UI thread.
Here are the contents of startWork():
void startWork()
{
// Naturally I cannot reference my listView1 control because it is in a
// different thread and is blocked the the "illegal" cross-thread check
int overallProgress = 0;
ListView.ListViewItemCollection items = null;
// This unfortunately doesn't work (MethodInvoker is in a different scope?)
listView1.BeginInvoke( new MethodInvoker(() => {
items = listView1.Items;
}));
int totalItems = items.Count; // "items" isn't recognized
foreach (ListViewItem files in items )
{
// slowwww work
}
}
I have also tried passing the ListView.ListViewItemCollection as an argument to the function with no avail.
Continuing to get Cross-thread operation not valid: accessed from a thread other than the thread it was created on
Note: The target framework is .NET 4.7 -- perhaps there is a better/more efficient method in newer versions of .NET?
I may just lack fundamental understanding of async/tasks, but I presume I am overlooking something important.
UI elements, including ListView.ListViewItemCollection and ListViewItem are "thread affine." This means they can only be accessed on the UI thread.
To do background work, you should only pass non-thread-affine objects. E.g., a List<string>, not a ListViewItemCollection or a List<ListViewItem>.
async void startParse_Click(object sender, EventArgs e)
{
var items = listView1.Items;
var data = /* extract List<string> from items */
await Task.Run(() => startWork(data));
}
void startWork(List<string> files)
{
int overallProgress = 0;
foreach (var file in files)
{
// slowwww work
}
}
Also, you shouldn't be using BeginInvoke. Use IProgress<T> with Progress<T> instead.
You don't have to iterate over items in a worker thread, as switching from one item in collection to another is pretty fast and do not freezes UI. Just move you "expensive" computational work to worker thread:
private async void StartParseButtonClick(object sender, EventArgs e)
{
// disable button (we are on UI thread)
var startParseButton = sender as Button;
startParseButton.Enabled = false;
try
{
// copy just in case if someone will add new item while we iterating over
var items = listView1.Items.OfType<ListViewItem>().ToList();
foreach (var item in items)
await Parse(item); // this will be invoked in worker thread
}
finally
{
// enable button finally (we are on UI thread)
startParseButton.Enabled = true;
}
}
private async Task Parse(ListViewItem item)
{
// slowwww work (we are on worker thread)
await Task.Delay(500);
}
Here's a simplified version of what I want to do:
onClick a button, a aNewMethod() would run asynchronously to keep UI responsive. That's it!
I've read some answers and here's what i could come up with :
private async void button_Click(object sender, RoutedEventArgs e)
{
Task task = Task.Run(() => aNewMethod());
await task;
}
private void aNewMethod()
{
if (progress.Value == 0)
{
//Heavy work
for (int i = 1; i < 1000000000; i++) { }
progress.Value = 100;
}
}
As you may have thought, this throws a System.InvalidOperationException at if(progress.Value== 0) saying :
The calling thread cannot access this object because a different
thread owns it.
after some Googling, I've read that I need a Dispatcher.BeginInvoke() method to update/use UI controls, so I did this :
private void aNewMethod()
{
Dispatcher.BeginInvoke((Action)delegate {
if (progress.Value == 0)
{
//Heavy work
for (int i = 1; i < 1000000000; i++) { }
progress.Value = 100;
}
});
}
This solved the System.InvalidOperationException but it's not running asynchronously as the UI still freezes at for loop
So the question is : How to run the aNewMethod(); asynchronously and still update and interact with UI controls ?
The Dispatcher runs in the UI thread. It handles your UI, and executes actions you pass to it via BeginInvoke etc.
But it can only handle one thing at a time; when it's busy handling your action, it won't update the UI in the meantime, so the UI freezes in the meantime.
If you want to keep your UI responsive, you'd need to run the heavy load functions in a seperate, non-UI thread. Within those functions running on another thread, you can call the dispatcher whenever you need access to the UI - ideally, only very briefly for the purpose of updating UI elements.
So in other words, you'd want to be running your sleep function in a seperate thread, and then just make a call to the Dispatcher from your own thread when you need to set the progress value. Something like
private void button_Click(object sender, RoutedEventArgs e)
{
Task task = Task.Run(() => aNewMethod()); // will call aNewMethod on the thread pool
}
private void aNewMethod()
{
double progressValue = 0;
Dispatcher.Invoke(() => progressValue = progress.Value);
if (progressValue == 0)
{
Thread.Sleep(3000); // still executes on the threadpool (see above), so not blocking UI
Dispatcher.Invoke(() => progress.Value = 100 ); // call the dispatcher to access UI
}
}
With you current implementation, there is no need to use Thread.Start, as in that method you are just sleeping it for some time and accessing UI thread objects there which is not allowed
.In your scenario a better way of doing is that you should not use Thread.Sleep instead of that you should be doing it with Task.Delay like:
private async void button_Click(object sender, RoutedEventArgs e)
{
if (progress.Value == 0)
{
await Task.Delay(3000);
progress.Value = 100;
}
}
Now you don't need Dispatcher.Invoke, and credit goes to async and await keywords as statements after await will be executing in the same calling synchronization context from where we did async call which is UI thread in this case.
onClick a button, a aNewMethod() would run asynchronously to keep UI responsive.
Actually, it's running synchronously on a background thread. Task.Run is perfectly appropriate for this.
after some Googling, I've read that I need a Dispatcher.BeginInvoke() method to update/use UI controls
Unfortunately, this is one area where Google will certainly mislead you. Dispatcher is not the best solution here.
Instead, you should use IProgress<T>/Progress<T>, as such:
private async void button_Click(object sender, RoutedEventArgs e)
{
var progress = new Progress<int>(value => { this.progress.Value = value; });
await Task.Run(() => aNewMethod(progress));
}
private void aNewMethod(IProgress<int> progress)
{
//Heavy work
for (int i = 1; i < 1000000000; i++) { }
progress.Report(100);
}
Does it right code, if I update my UI controls in task like this?
Or it's wrong, and I need use smth like Control.Invoke?
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text = await Task<string>.Factory.StartNew(() =>
{
Foo();
return "Completed";
});
}
private void Foo()
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
Thread.Sleep(1000);
}
}
The BCL addresses this specific scenario with the IProgress interface, implemented in the Progress class, to provide rich asynchronous progress reporting. This is available in .NET 4.5, or .NET 4 with the BCL Portability Nuget package. A lot of BCL classes accept an IProgress parameter for progress reporting.
Servy's answer addresses the immediate problem of how to update the UI after an asynchronous operation, but that forces you to mix UI code inside the long running operation. IProgress allows you to make an OnReport call with your report data without any concerns about marshalling the call to the proper thread, synchronization contexts, UI specific calls etc.
Your code can be as simple as this:
private async void button1_Click(object sender, EventArgs e)
{
var progress=new Progress<string>(msg=>textBox1.Text = msg);
await Task<string>.Factory.StartNew(() => Foo(progress));
}
private void Foo(IProgress<string> progress)
{
for (int i = 0; i < 100; i++)
{
progress.OnReport(i.ToString());
Thread.Sleep(1000);
}
progress.OnReport("Finished");
}
Or you can use a more complex progress type, eg
class MyProgressData
{
public string Message{get;set;}
public int Iteration {get;set;}
public MyProgressData(string message,int iteration) ...
}
private async void button1_Click(object sender, EventArgs e)
{
var progress=new Progress<MyProgressData>(msg=>{
textBox1.Text = msg.Message;
textBox2.Text=msg.Iteration.ToString();
});
await Task<string>.Factory.StartNew(() => Foo(progress));
}
private void Foo(IProgress<MyProgressData> progress)
{
for (int i = 0; i < 100; i++)
{
progress.OnReport(new MyProgressData("Hi",i));
Thread.Sleep(1000);
}
progress.OnReport("Finished");
}
The beauty of this is that you can completely decouple processing from reporting. You can put the processing code in a completely different class or even project from your UI.
You can just run the code to see that it won't work, and that your program will crash, as you are touching the UI from a non-UI thread.
You should instead update the UI as a continuation to the task that is scheduled to run in the UI thread. await does all of this for you, making the code pretty trivial.
You also shouldn't create a thread pool thread just to have it sit there and do nothing while you sleep for a fixed amount of time. Use Task.Delay instead.
private async void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
textBox1.Text = i.ToString();
await Task.Delay(1000);
}
textBox1.Text = "Completed";
}
Your Foo method will throw, since you're trying to update a UI control from a background thread.
If Foo did something arbitrary, which doesn't evolve any UI controls, then your textBox1.Text = await Task.Factory.StartNew would be fine, since you use await and the SynchronizationContext would be implicitly captured and used once the await completes, which would make the assignment on the UI thread.
This doesn't make too much sense, but if you wanted to update a control from inside the Task, you'd have to use Control.Invoke.
I am currently writing my first program on C# and I am extremely new to the language (used to only work with C so far). I have done a lot of research, but all answers were too general and I simply couldn't get it t work.
So here my (very common) problem:
I have a WPF application which takes inputs from a few textboxes filled by the user and then uses that to do a lot of calculations with them. They should take around 2-3 minutes, so I would like to update a progress bar and a textblock telling me what the current status is.
Also I need to store the UI inputs from the user and give them to the thread, so I have a third class, which I use to create an object and would like to pass this object to the background thread.
Obviously I would run the calculations in another thread, so the UI doesn't freeze, but I don't know how to update the UI, since all the calculation methods are part of another class.
After a lot of reasearch I think the best method to go with would be using dispatchers and TPL and not a backgroundworker, but honestly I am not sure how they work and after around 20 hours of trial and error with other answers, I decided to ask a question myself.
Here a very simple structure of my program:
public partial class MainWindow : Window
{
public MainWindow()
{
Initialize Component();
}
private void startCalc(object sender, RoutedEventArgs e)
{
inputValues input = new inputValues();
calcClass calculations = new calcClass();
try
{
input.pota = Convert.ToDouble(aVar.Text);
input.potb = Convert.ToDouble(bVar.Text);
input.potc = Convert.ToDouble(cVar.Text);
input.potd = Convert.ToDouble(dVar.Text);
input.potf = Convert.ToDouble(fVar.Text);
input.potA = Convert.ToDouble(AVar.Text);
input.potB = Convert.ToDouble(BVar.Text);
input.initStart = Convert.ToDouble(initStart.Text);
input.initEnd = Convert.ToDouble(initEnd.Text);
input.inita = Convert.ToDouble(inita.Text);
input.initb = Convert.ToDouble(initb.Text);
input.initc = Convert.ToDouble(initb.Text);
}
catch
{
MessageBox.Show("Some input values are not of the expected Type.", "Wrong Input", MessageBoxButton.OK, MessageBoxImage.Error);
}
Thread calcthread = new Thread(new ParameterizedThreadStart(calculations.testMethod);
calcthread.Start(input);
}
public class inputValues
{
public double pota, potb, potc, potd, potf, potA, potB;
public double initStart, initEnd, inita, initb, initc;
}
public class calcClass
{
public void testmethod(inputValues input)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
int i;
//the input object will be used somehow, but that doesn't matter for my problem
for (i = 0; i < 1000; i++)
{
Thread.Sleep(10);
}
}
}
I would be very grateful if someone had a simple explanation how to update the UI from inside the testmethod. Since I am new to C# and object oriented programming, too complicated answers I will very likely not understand, I'll do my best though.
Also if someone has a better idea in general (maybe using backgroundworker or anything else) I am open to see it.
First you need to use Dispatcher.Invoke to change the UI from another thread and to do that from another class, you can use events.
Then you can register to that event(s) in the main class and Dispatch the changes to the UI and in the calculation class you throw the event when you want to notify the UI:
class MainWindow : Window
{
private void startCalc()
{
//your code
CalcClass calc = new CalcClass();
calc.ProgressUpdate += (s, e) => {
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
};
Thread calcthread = new Thread(new ParameterizedThreadStart(calc.testMethod));
calcthread.Start(input);
}
}
class CalcClass
{
public event EventHandler ProgressUpdate;
public void testMethod(object input)
{
//part 1
if(ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs(status));
//part 2
}
}
UPDATE:
As it seems this is still an often visited question and answer I want to update this answer with how I would do it now (with .NET 4.5) - this is a little longer as I will show some different possibilities:
class MainWindow : Window
{
Task calcTask = null;
void buttonStartCalc_Clicked(object sender, EventArgs e) { StartCalc(); } // #1
async void buttonDoCalc_Clicked(object sender, EventArgs e) // #2
{
await CalcAsync(); // #2
}
void StartCalc()
{
var calc = PrepareCalc();
calcTask = Task.Run(() => calc.TestMethod(input)); // #3
}
Task CalcAsync()
{
var calc = PrepareCalc();
return Task.Run(() => calc.TestMethod(input)); // #4
}
CalcClass PrepareCalc()
{
//your code
var calc = new CalcClass();
calc.ProgressUpdate += (s, e) => Dispatcher.Invoke((Action)delegate()
{
// update UI
});
return calc;
}
}
class CalcClass
{
public event EventHandler<EventArgs<YourStatus>> ProgressUpdate; // #5
public TestMethod(InputValues input)
{
//part 1
ProgressUpdate.Raise(this, status); // #6 - status is of type YourStatus
// alternative version to the extension for C# 6+:
ProgressUpdate?.Invoke(this, new EventArgs<YourStatus>(status));
//part 2
}
}
static class EventExtensions
{
public static void Raise<T>(this EventHandler<EventArgs<T>> theEvent,
object sender, T args)
{
if (theEvent != null)
theEvent(sender, new EventArgs<T>(args));
}
}
#1) How to start the "synchronous" calculations and run them in the background
#2) How to start it "asynchronous" and "await it": Here the calculation is executed and completed before the method returns, but because of the async/await the UI is not blocked (BTW: such event handlers are the only valid usages of async void as the event handler must return void - use async Task in all other cases)
#3) Instead of a new Thread we now use a Task. To later be able to check its (successfull) completion we save it in the global calcTask member. In the background this also starts a new thread and runs the action there, but it is much easier to handle and has some other benefits.
#4) Here we also start the action, but this time we return the task, so the "async event handler" can "await it". We could also create async Task CalcAsync() and then await Task.Run(() => calc.TestMethod(input)).ConfigureAwait(false); (FYI: the ConfigureAwait(false) is to avoid deadlocks, you should read up on this if you use async/await as it would be to much to explain here) which would result in the same workflow, but as the Task.Run is the only "awaitable operation" and is the last one we can simply return the task and save one context switch, which saves some execution time.
#5) Here I now use a "strongly typed generic event" so we can pass and receive our "status object" easily
#6) Here I use the extension defined below, which (aside from ease of use) solve the possible race condition in the old example. There it could have happened that the event got null after the if-check, but before the call if the event handler was removed in another thread at just that moment. This can't happen here, as the extensions gets a "copy" of the event delegate and in the same situation the handler is still registered inside the Raise method.
I am going to throw you a curve ball here. If I have said it once I have said it a hundred times. Marshaling operations like Invoke or BeginInvoke are not always the best methods for updating the UI with worker thread progress.
In this case it usually works better to have the worker thread publish its progress information to a shared data structure that the UI thread then polls at regular intervals. This has several advantages.
It breaks the tight coupling between the UI and worker thread that Invoke imposes.
The UI thread gets to dictate when the UI controls get updated...the way it should be anyway when you really think about it.
There is no risk of overrunning the UI message queue as would be the case if BeginInvoke were used from the worker thread.
The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
You get more throughput on both the UI and worker threads.
Invoke and BeginInvoke are expensive operations.
So in your calcClass create a data structure that will hold the progress information.
public class calcClass
{
private double percentComplete = 0;
public double PercentComplete
{
get
{
// Do a thread-safe read here.
return Interlocked.CompareExchange(ref percentComplete, 0, 0);
}
}
public testMethod(object input)
{
int count = 1000;
for (int i = 0; i < count; i++)
{
Thread.Sleep(10);
double newvalue = ((double)i + 1) / (double)count;
Interlocked.Exchange(ref percentComplete, newvalue);
}
}
}
Then in your MainWindow class use a DispatcherTimer to periodically poll the progress information. Configure the DispatcherTimer to raise the Tick event on whatever interval is most appropriate for your situation.
public partial class MainWindow : Window
{
public void YourDispatcherTimer_Tick(object sender, EventArgs args)
{
YourProgressBar.Value = calculation.PercentComplete;
}
}
You're right that you should use the Dispatcher to update controls on the UI thread, and also right that long-running processes should not run on the UI thread. Even if you run the long-running process asynchronously on the UI thread, it can still cause performance issues.
It should be noted that Dispatcher.CurrentDispatcher will return the dispatcher for the current thread, not necessarily the UI thread. I think you can use Application.Current.Dispatcher to get a reference to the UI thread's dispatcher if that's available to you, but if not you'll have to pass the UI dispatcher in to your background thread.
Typically I use the Task Parallel Library for threading operations instead of a BackgroundWorker. I just find it easier to use.
For example,
Task.Factory.StartNew(() =>
SomeObject.RunLongProcess(someDataObject));
where
void RunLongProcess(SomeViewModel someDataObject)
{
for (int i = 0; i <= 1000; i++)
{
Thread.Sleep(10);
// Update every 10 executions
if (i % 10 == 0)
{
// Send message to UI thread
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(Action)(() => someDataObject.ProgressValue = (i / 1000)));
}
}
}
Everything that interacts with the UI must be called in the UI thread (unless it is a frozen object). To do that, you can use the dispatcher.
var disp = /* Get the UI dispatcher, each WPF object has a dispatcher which you can query*/
disp.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => /*Do your UI Stuff here*/));
I use BeginInvoke here, usually a backgroundworker doesn't need to wait that the UI updates. If you want to wait, you can use Invoke. But you should be careful not to call BeginInvoke to fast to often, this can get really nasty.
By the way, The BackgroundWorker class helps with this kind of taks. It allows Reporting changes, like a percentage and dispatches this automatically from the Background thread into the ui thread. For the most thread <> update ui tasks the BackgroundWorker is a great tool.
If this is a long calculation then I would go background worker. It has progress support. It also has support for cancel.
http://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Here I have a TextBox bound to contents.
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("backgroundWorker_RunWorkerCompleted");
if (e.Cancelled)
{
contents = "Cancelled get contents.";
NotifyPropertyChanged("Contents");
}
else if (e.Error != null)
{
contents = "An Error Occured in get contents";
NotifyPropertyChanged("Contents");
}
else
{
contents = (string)e.Result;
if (contentTabSelectd) NotifyPropertyChanged("Contents");
}
}
You are going to have to come back to your main thread (also called UI thread) in order to update the UI.
Any other thread trying to update your UI will just cause exceptions to be thrown all over the place.
So because you are in WPF, you can use the Dispatcher and more specifically a beginInvoke on this dispatcher. This will allow you to execute what needs done (typically Update the UI) in the UI thread.
You migh also want to "register" the UI in your business, by maintaining a reference to a control/form, so you can use its dispatcher.
Thank God, Microsoft got that figured out in WPF :)
Every Control, like a progress bar, button, form, etc. has a Dispatcher on it. You can give the Dispatcher an Action that needs to be performed, and it will automatically call it on the correct thread (an Action is like a function delegate).
You can find an example here.
Of course, you'll have to have the control accessible from other classes, e.g. by making it public and handing a reference to the Window to your other class, or maybe by passing a reference only to the progress bar.
Felt the need to add this better answer, as nothing except BackgroundWorker seemed to help me, and the answer dealing with that thus far was woefully incomplete. This is how you would update a XAML page called MainWindow that has an Image tag like this:
<Image Name="imgNtwkInd" Source="Images/network_on.jpg" Width="50" />
with a BackgroundWorker process to show if you are connected to the network or not:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
private BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up background worker to allow progress reporting and cancellation
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
// This is your main work process that records progress
bw.DoWork += new DoWorkEventHandler(SomeClass.DoWork);
// This will update your page based on that progress
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
// This starts your background worker and "DoWork()"
bw.RunWorkerAsync();
// When this page closes, this will run and cancel your background worker
this.Closing += new CancelEventHandler(Page_Unload);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapImage bImg = new BitmapImage();
bool connected = false;
string response = e.ProgressPercentage.ToString(); // will either be 1 or 0 for true/false -- this is the result recorded in DoWork()
if (response == "1")
connected = true;
// Do something with the result we got
if (!connected)
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_off.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
else
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_on.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
}
private void Page_Unload(object sender, CancelEventArgs e)
{
bw.CancelAsync(); // stops the background worker when unloading the page
}
}
public class SomeClass
{
public static bool connected = false;
public void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
int i = 0;
do
{
connected = CheckConn(); // do some task and get the result
if (bw.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
// Record your result here
if (connected)
bw.ReportProgress(1);
else
bw.ReportProgress(0);
}
}
while (i == 0);
}
private static bool CheckConn()
{
bool conn = false;
Ping png = new Ping();
string host = "SomeComputerNameHere";
try
{
PingReply pngReply = png.Send(host);
if (pngReply.Status == IPStatus.Success)
conn = true;
}
catch (PingException ex)
{
// write exception to log
}
return conn;
}
}
For more information: https://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
I am trying to create some UserControl(s) using another thread, and I am using code like this:
private void btnDemo_Click(object sender, RoutedEventArgs e)
{
Task tsk = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 3; i++)
{
MyControl sprite = new MyControl();
pnlTest.Children.Add(sprite);
}
});
}
But I am getting this exception in the UserControl constructor:
The calling thread must be STA, because many UI components require this.
I am not sure that I am using the right approach to do this. Please, Can you help me with this.
thanks.
The creating of the controls can be done on any Thread but Adding them to the GUI needs to be synchronized to the main Thread.
In this case, just 3 controls, forget about Tasks and just do it directly, single-threaded.
You can dispatch the operation of adding controls to the Children collection to the UI thread using Dispatcher:
private void btnDemo_Click(object sender, RoutedEventArgs e)
{
Task tsk = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 3; i++)
{
Dispatcher.BeginInvoke(new Action(() => {
MyControl sprite = new MyControl();
pnlTest.Children.Add(sprite);
}));
}
});
}
By calling BeginInvoke on Dispatcher you basically adding the operation to the queue to execute on the UI thread.