In a C#.NET windows application (winforms) I set the visibility of the checkbox to false:
checkBoxLaunch.Visible = true;
I started a thread.
Thread th = new Thread(new ThreadStart(PerformAction));
th.IsBackground = true;
th.Start();
The thread performs some stuff and sets the visibility to true:
private void PerformAction()
{
/*
.
.// some actions.
*/
checkBoxLaunch.Visible = true;
}
After the thread finishes its task, the checkbox is not visible to me.
What am I missing?
You shouldn't make UI changes within a non-UI thread. Use Control.Invoke, Control.BeginInvoke or BackgroundWorker to marshal the call back to the UI thread. For example (assuming C# 3):
private void PerformAction()
{
/*
.
.// some actions.
*/
MethodInvoker action = () => checkBoxLaunch.Visible = true;
checkBoxLaunch.BeginInvoke(action);
}
Search for any of Control.Invoke, Control.BeginInvoke or BackgroundWorker to find hundreds of articles about this.
Related
According to answer for this question Why Thread.Join() DOES NOT hang my application when called on UI thread? thread.Join should not hang UI if it called from STA thread. I used the same code as in linked question
private void button1_Click(object sender, EventArgs e)
{
string retValue = "";
Thread thread = new Thread(
() =>
{
retValue = LongRunningHeavyFunction();
});
thread.Start();
thread.Join();
button1.Text = retValue;
}
private string LongRunningHeavyFunction()
{
Thread.Sleep(5000);
return "Done";
}
Method Main in class Program marked as [STAThread]. But when I press button UI is freezed, I can't drag window etc. I'm confused. Am I missed something? Why UI is freezed in my case?
Thread.Sleep causes UI to freeze.
If you want to wait for a while in LongRunningHeavyFunction(), use a timer object.
Here is an example, how to use timer:
How to use a timer to wait?
thread.Join() tells the current thread to await thread. In this case, the current thread is the GUI thread, and you're telling it to await the worker thread. As a result, your GUI thread does nothing until the worker thread completes. And since the GUI thread is doing nothing, it isn't handling normal GUI activities, causing the freeze.
The solution is to not block your GUI. Instead, run your long-running process without awaiting it, such that your GUI thread can keep responding to the user. Then, once the long-running process does complete, use the GUI dispatcher to call back to set the result.
The code might look something like this:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(
() =>
{
// Perform work
var retValue = LongRunningHeavyFunction();
// Call the GUI thread
button1.Dispatcher.BeginInvoke(() =>
{
// .Dispatcher called the GUI thread.
// This code happens back in the GUI thread once the
// worker thread has completed.
button1.Text = retValue;
});
});
thread.Start();
}
private string LongRunningHeavyFunction()
{
Thread.Sleep(5000);
return "Done";
}
I'm beginner in c#,and i write this code for start the new thread:
Thread workerThread = new Thread(DoWork);
workerThread.Priority = ThreadPriority.Highest;
workerThread.Start();
in the up thread process some thing and show into the chart,every thing is okay,but when run and finish DoWork method,chart control visible set to false automatically!,my DoWork method is:
public void DoWork()
{
//.....some process and show into the process result into the chart
chart1.Visible = true;//this code not run
}
how can solve that?
You do not have access to UI elements from a different thread.
For Winforms:
How to update the GUI from another thread in C#?
For WPF:
Change WPF controls from a non-main thread using Dispatcher.Invoke
chart1.Dispatcher.Invoke(() =>chart1.Visible = true);
Change your Dowork method signature to accept object as parameter and pass Synchronization context to it:
void DoWork(object o)
{
SynchronizationContext cont = o as SynchronizationContext;
// your logic gere
cont.Post(delegate
{
// all your UI updates here
}, null);
}
Thread workerThread = new Thread(DoWork);
workerThread.Priority = ThreadPriority.Highest;
workerThread.Start(SynchronizationContext.Current);
I have my VM implemented INotifyPropertyChanged interface. I created another thread T for populating a list that I bind to Xaml. After list is populated, I call PropertyChanged in thread T, and my UI got refreshed correctly.
My question is in what case I would need to use Dispatcher? Why I don't need to use Dispatcher in my case? I thought Dispatcher is used when the code in other thread want to notify the changes to the UI thread by enqueuing the changes to the UI refresh queue, such as adding items to ObservableCollection from another thread, and UI thread will then pull data from the queue.
private List<string> _ListData;
public List<String> ListData
{
get
{
if (_ListData == null)
Initialise( () => ListData = ReturnSlow());
return _ListData;
}
set { _ListData = value; }
}
private List<string> ReturnSlow()
{
List<string> Test = new List<string>();
Test.Add("1");
Test.Add("2");
Thread.Sleep(2000);
return Test;
}
public void Initialise(Action initialiser)
{
Task t = new Task(() =>
{
initialiser();
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("ListData"));
});
t.Start();
}
Your app has a main UI thread (usually ManagedThreadId==1). If you want to update the UI from an event that gets pull on some other thread you must use the dispatcher. A useful test here is the Dispatcher.CheckAccess() method that returns true if code is on UI thread and false if on some other thread. A typical call looks something like:
using System.Windows.Threading; // For Dispatcher.
if (Application.Current.Dispatcher.CheckAccess()) {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}));
}
If you're in the main window you can use:
Dispatcher.BeginInvoke(...
If you're in someother context eg a view model then use:
Application.Current.Dispatcher.BeginInvoke(
Invoke vs BeginInvoke
Use Invoke if you want the current thread to wait until the UI thread has processed the dispatch code or BeginInvoke if you want current thread to continue without waiting for operation to complete on UI thread.
MessageBox, Dispatchers and Invoke/BeginInvoke:
Dispatcher.Invoke will block your thread until the MessageBox is dismissed.
Dispatcher.BeginInvoke will allow your thread code to continue to execute while the UI thread will block on the MessageBox call until its dismissed.
CurrentDispatcher vs Current.Dispatcher!
Be ware of Dispatcher.CurrentDispatcher as my understanding of this is that is will return a Dispatcher for the current thread not the UI thread. Generally are you interested in the dispatcher on the UI thread - Application.Current.Dispatcher always returns this.
Additional note:
If you are finding you are having to check dispatcher CheckAccess often then a useful helper method is:
public void DispatchIfNecessary(Action action) {
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(action);
else
action.Invoke();
}
Which can be called as:
DispatchIfNecessary(() => {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});
I have faced with a problem of threads synchronization. My presenter analyzes some sensors and update UI form. I moved updating code into separate thread. It works fine, but if the user stops presenter when it is updating the view, the software freezes - I found that it happens when view.UpdateUI working (it just set some labels using Invoke). Where my problem is? I use compact framework 3.5 and Windows CE 5
using System.Threading;
class MyPresenter
{
UserControl view;
private Thread thread;
private ManualResetEvent cancelEvent;
public void Start()
{
cancelEvent = new ManualResetEvent(false);
thread = new Thread(UpdateView) { IsBackground = true };
thread.Start();
}
public void Stop()
{
if (thread != null) {
cancelEvent.Set();
thread.Join();
thread = null;
}
}
private void UpdateView()
{
while (cancelEvent.WaitOne(1000, false) == false) {
// analyze something
view.UpdateUI(...);
}
}
}
Don't update the UI thread directly from within a worker thread. Use a delegate instead.
For example: How to update the GUI from another thread in C#?
If your background thread is blocked calling your UI (via Control.Invoke), and then your UI thread is blocked calling your Stop method with its thread.Join() you've got yourself a classic fatal embrace. You should get rid of the Join and instead have the background thread raise one last event / notification when the Stop completes so the UI can deal with that (enable/disable buttons etc).
I have a UserControl with a tree on it. It uses multithreading to add nodes to it. I have a function called Expand which I need to execute after filtering completed and since I'm a newbie with multithreading I'm not sure how to do that. Here's my code:
class MyClass : UserControl
{
private Thread nThread;
private bool searchLoadCompleted = false;
private void Filter()
{
ClearTree();
this.nThread = new Thread(new ParameterizedThreadStart(AddFilteredResultsToTree));
this.nThread.IsBackground = true;
this.nThread.Start(someParameter);
}
private void AddFilteredResultsToTree(int someParameter)
{
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = false ));
myTree.Invoke(new MethodInvoker( ()=> AppendNode(......) ));
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = true ));
}
private void Expand()
{
}
}
I tried to add nThread.Join() into Expand() but it got stuck indefinitely. What should I do?
If the singlethreaded version of this is:
ClearTree();
AddFilteredResultsToTree(someparameter);
Expand();
Don't bother going multithreading, just do it on the same thread. The point of using multithreading there would be to let the main thread handle UI events, if you join the thread then you're basically just launching a background thread while freezing (not doing any work) in the main thread. Note that by calling Invoke you're actually delegating the execution of AddFilteredResultsToTree to the main thread anyway.
I'd suggest you simply call Expand from AddFilteredResult and use the Dispatcher to update the UI if needed or.
Another way to go (best in my opinion) would be to use the Async Pattern for this (example and tutorial here), and then on the AsyncCallback update the UI.
Calling Invoke will block both the GUI thread and your worker thread so there won't be any performance improvement over code without a worker thread.