WPF control is not refreshed properly - c#

I am having an issue with refresh for a normal text block. My code is as follows:
public Window1()
{
InitializeComponent();
Thread newt = new Thread(Tick);
newt.Start();
}
void Tick()
{
while (true)
{
textBlock1.Dispatcher.Invoke(
DispatcherPriority.Normal,
new Action(
delegate()
{
textBlock1.Text = DateTime.Now.ToString("h:mm:ss");
Thread.Sleep(1000);
}
));
}
}
With the application running, the monitor goes to sleep mode at 12:55:55. When I reactivate the monitor at 1:02, I noticed that the value is updated each second, however as the hour has no ten's unit now, it is left aligned and the unit's place of the seconds of 12:55:55 is not refreshed.
So, it shows the value as: 1:02:555. The last 5 is from the 12:55:55 before the monitor went to sleep.
The control is only refreshed after I minimize and maximize the window in which case it shows the time correctly properly refreshed.
It's a display driver issue with NVidia FX 1800. Has anyone ran into the same problem?

Set the dispatcher priority to a lower one, this will make sure your text box is refreshed.

Try to use textBox.InvalidateVisual(). It forces the textbox to rerender. But it has performance impacts as the control should know itself very exact what part should get rerendered

You are putting the UI thread to sleep for a 1 second before returning. You should not put the UI thread to sleep. I believe you intended for your background thread to sleep for 1 second, if so then you'd need to do:
void Tick()
{
while (true)
{
textBlock1.Dispatcher.Invoke(
DispatcherPriority.Normal,
new Action(
delegate()
{
textBlock1.Text = DateTime.Now.ToString("h:mm:ss");
}
));
// Executed on background thread, not UI thread
Thread.Sleep(1000);
}
}

Related

Create a WPF Progress Window on another thread

I'm creating a custom add-in command through the API of a piece of architectural modeling software called Revit. My command may take some time to complete so I want to show the user a window with a progress bar as it is working.
Typically if I were to create a progress window like this it would be on the main UI thread, and the actual work being done would happen on a secondary worker thread. However, Revit requires that any access to the API be through the thread calling the custom command. So I must create my progress bar on a second thread.
I found this blog post about launching a WPF window in a separate thread, and based my solution on it. Here's my custom command class.
public class SampleProgressWindowCommand : Autodesk.Revit.UI.IExternalCommand
{
private ProgressWindow progWindow;
internal static EventWaitHandle _progressWindowWaitHandle;
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
//Starts New Progress Window Thread
using (_progressWindowWaitHandle = new AutoResetEvent(false))
{
//Starts the progress window thread
Thread newprogWindowThread = new Thread(new ThreadStart(ShowProgWindow));
newprogWindowThread.SetApartmentState(ApartmentState.STA);
newprogWindowThread.IsBackground = true;
newprogWindowThread.Start();
//Wait for thread to notify that it has created the window
_progressWindowWaitHandle.WaitOne();
}
//Does some work that takes a long time
for (int i = 1; i <= 100; i++)
{
//Updates Progress
this.progWindow.UpdateProgress("Item " + i.ToString(), i, 100);
//Does some fake work
System.Threading.Thread.Sleep(700);
}
//closes the Progress window
progWindow.Dispatcher.Invoke(new Action(progWindow.Close));
//Show Result to User
Autodesk.Revit.UI.TaskDialog.Show("Task", "Task Completed");
return Result.Succeeded;
}
private void ShowProgWindow()
{
//creates and shows the progress window
progWindow = new ProgressWindow();
progWindow.Show();
//makes sure dispatcher is shut down when the window is closed
progWindow.Closed +=new EventHandler(progWindow_Closed);
//Notifies command thread the window has been created
_progressWindowWaitHandle.Set();
//Starts window dispatcher
System.Windows.Threading.Dispatcher.Run();
}
}
And here is the UpdateProgress() method on my ProgressWindow class
public void UpdateProgress(string message, int current, int total)
{
this.Dispatcher.Invoke(new Action<string, int, int>(
delegate(string m, int v, int t)
{
this.progressBar1.Maximum = System.Convert.ToDouble(t);
this.progressBar1.Value = System.Convert.ToDouble(v);
this.messageLbl.Content = m;
}),
System.Windows.Threading.DispatcherPriority.Background,
message, current, total);
}
My first question is in general did I do this right? It seems to work, but I know enough about multithreaded programing to know that just because it works today, does not mean it's going to work tomorrow.
Second, I would like to add a cancel button to my progress window to be able to cancel the process. What is the best way to do this? I understand that ultimately I'll end up with a "cancelRequested" boolean flag that is checked regularly by the working thread, but how do I set this from the progress window thread?
The only improvement that I can see is that you have a potential race condition between setting your AutoResetEvent and calling Dispatcher.Run. I know because I've run into this issue in my own use of multi-threaded progress UIs.
The way to fix it is to BeginInvoke the call on the background Dispatcher. This will ensure it executes after the Dispatcher has begun pumping events:
System.Windows.Threading.Dispatcher.Current.BeginInvoke(
new Func<bool>(_progressWindowWaitHandle.Set));

Update MainWindow on Timer.Elapsed event

I am writing a home WPF app that is obtaining a file from a server at a configured interval.
It's a basic window, with a couple of labels. I have the following
Start Time (reflects DateTime the "Start" event was hit
Duration (reflects the time the app has been running)
Speed (the download speed of the file)
I want to update the Duration on the Main window each second so I have the following code to do this (in a seperate class "RunDownloader.cs").
private void StartTickTimer()
{
const double interval = 1000;
if (_tickTimer == null)
{
_tickTimer = new Timer
{
Interval = interval
};
_tickTimer.Elapsed += _ticktimer_Elapsed;
}
_tickTimer.Start();
}
On _ticktimer_Elapsed I call a method in the main window _mainWindow.UpdateTicker();
This does the following.
public void UpdateTicker()
{
var timeStarted = lblTimeStarted.Content.ToString();
DateTime startTime = DateTime.Parse(timeStarted);
TimeSpan span = DateTime.Now.Subtract(startTime);
//ToDo: Output time taken here!
//lblTimeElapsed.Content =
}
I have two issues.
I have the following exception when calling lblTimeStarted.Content.ToString(); in UpdateTicker()
"The calling thread cannot access this object because a different thread owns it."
I dont quite know, how to show the duration correctly for lblTimeElapsed.Content from TimeSpan
Thanks in advance for any answers. :D
In WPF you cannot update UI objects (that get created on the UI thread) from threads other than the UI thread.
In order to update UI controls from some other thread (eg a timer thread) you need to use the Dispatcher to run your update code on the UI thread.
This Question/answer may help you or you will find plenty of info by googling "WPF Dispatcher".
An example dispatcher call - the lamda code will get posted off to run on the UI thread:
Dispatcher.BeginInvoke(new Action(() =>
{
text_box.AppendText(formated_msg);
text_box.ScrollToEnd();
}));
Alternatively you could replace your existing timer with a DispatchTimer - unlike the timer you are using it ensures that the timer callback is on the UI thread:
Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.
Your timer is running on its own thread and invoking the UpdateTicker() method from there. However, most UI frameworks, including WPF, prohibit accessing UI controls from threads other than the one which the respective control was created on (the latter is usually denoted as the "UI thread"). You have two main options here:
Use a DispatcherTimer. This will run on your UI thread and avoids any threading issues, but then, since your UpdateTicker() code also runs on this thread, your UI will be unresponsive while you are doing processing. This may or may not be an issue; if all you do is a couple of field/property changes, this is fine.
In your timer callback, use this.Dispatcher.Invoke() or this.Dispatcher.BeginInvoke() to call your UI update method once other processing is completed (example: this.Dispatcher.Invoke((Action) UpdateTicker)). This will "bump" the call to the proper thread for the UI update, while maintaining the asynchrony for data processing. In other words, this is a more effective approach.
The TimeSpan struct has a ToString() method that accepts formatting; or, if this is inconvenient, it has several helper properties (Days, Hours, Minutes, TotalDays, TotalHours, TotalMinutes etc.) that you can use for display purposes.
You can do it like:
In main windows:
public void ChangeTime(string time)
{
lblsb.Content = time;
}
And in RunDownloader:
class RunDownloader
{
Timer _tickTimer;
MainWindow window;
public RunDownloader(MainWindow window)
{
this.window = window;
}
private delegate void MyDel(string str);
public void StartTickTimer()
{
const double interval = 1000;
if (_tickTimer == null)
{
_tickTimer = new Timer
{
Interval = interval
};
_tickTimer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
window.Dispatcher.BeginInvoke(new MyDel(window.ChangeTime), DateTime.Now.ToLongDateString());
};
}
_tickTimer.Start();
}
}

How do I update GUI after each iteration?

I have a label and canvas representing a coordinate system. In the canvas there is a node, which should change it's place every time a calculation is made. This is done until a specific stopping criteria is meet.
I also have a label containing coordinate info for the note. I want to be able to see the node and label update on every iteration(every time the calculation is made).
I have looked a the dispatcher, but my GUI will only update when the calculations are done. Below is what I have tried doing with the Dispatcher for the label.
While(notDone = true){
//Calculations made here
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => this.aLabel.Text = aString ));
}
I have been looking at solutions for similar problems and some solutions involve threads. Do I have to use threads to update my GUI?
.Net has a class exactly for you, my friend!
BackgroundWorker
Do all the heavy lifting (your loop) in the DoWork method and update your GUI in ReportProgress.
See the documentation for help.
Just create delegate and event for handling information changes
public delegate void SomeInfoChangeDelegate(object o);
public event SomeInfoChangeDelegate InfoChangeEvent = null;
Assign listener to event and start thread w/ calculations
InfoChangeEvent += new SomeInfoChangeDelegate(OnInfoChanged);
Thread t = new Thread(new ParameterizedThreadStart(SomeWorkerThread));
t.Start();
Make calculation thread and event listener
void OnInfoChanged(object o)
{
// Update label
}
protected void SomeWorkerThread(object o)
{
int i = 0;
while(true)
{
if( i % 10 == 0 )
{
if(InfoChangeEvent != null)
{
InfoChangeEvent(i);
}
}
Thread.Sleep(1000);
i++;
}
}
And don't forget to stop thread :)
If you're performing calculations in UI (main) thread, it can't process messages until they're done. Move calculations to another thread and notify main thread in each iteration.
If you use WPF/Silverlight make class with INotifyPropertyChanged implemented and bind element positions to properties. On RaisePropertyChanged("PropName") position 'll be changed.

How to asynchronously wait for x seconds and execute something then?

I know there is Thread.Sleep and System.Windows.Forms.Timer and Monitor.Wait in C# and Windows Forms. I just can't seem to be able to figure out how to wait for X seconds and then do something else - without locking the thread.
I have a form with a button. On button click a timer shall start and wait for 5 seconds. After these 5 seconds some other control on the form is colored green. When using Thread.Sleep, the whole application would become unresponsive for 5 seconds - so how do I just "do something after 5 seconds"?
(transcribed from Ben as comment)
just use System.Windows.Forms.Timer. Set the timer for 5 seconds, and handle the Tick event. When the event fires, do the thing.
...and disable the timer (IsEnabled=false) before doing your work in oder to suppress a second.
The Tick event may be executed on another thread that cannot modify your gui, you can catch this:
private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private void StartAsyncTimedWork()
{
myTimer.Interval = 5000;
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
}
private void myTimer_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
/* Not on UI thread, reenter there... */
this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
}
else
{
lock (myTimer)
{
/* only work when this is no reentry while we are already working */
if (this.myTimer.Enabled)
{
this.myTimer.Stop();
this.doMyDelayedWork();
this.myTimer.Start(); /* optionally restart for periodic work */
}
}
}
}
Just for completeness: with async/await, one can delay execute something very easy (one shot, never repeat the invocation):
private async Task delayedWork()
{
await Task.Delay(5000);
this.doMyDelayedWork();
}
//This could be a button click event handler or the like */
private void StartAsyncTimedWork()
{
Task ignoredAwaitableResult = this.delayedWork();
}
For more, see "async and await" in MSDN.
more completeness:
Depending on your Framework, there is a good chance you will have DispatcherTimer class that can handle the invocation internally (WPF-variants). (finde details in ms docs)
Have you tried
public static Task Delay(
int millisecondsDelay
)
You can use like this:
await Task.Delay(5000);
reference: https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx
You can start an asynchronous task that performs your action:
Task.Factory.StartNew(()=>
{
Thread.Sleep(5000);
form.Invoke(new Action(()=>DoSomething()));
});
[EDIT]
To pass the interval in you simply have to store it in a variable:
int interval = 5000;
Task.Factory.StartNew(()=>
{
Thread.Sleep(interval);
form.Invoke(new Action(()=>DoSomething()));
});
[/EDIT]
You can wait UI thread the way you want it to work.
Task.Factory.StartNew(async() =>
{
await Task.Delay(2000);
// it only works in WPF
Application.Current.Dispatcher.Invoke(() =>
{
// Do something on the UI thread.
});
});
if you're using .Net Framework 4.5 or higher version, you can use Task.Run instead of Task.Factory.StartNew just like below.
int millisecondsDelay = 2000;
Task.Run(async() =>
{
await Task.Delay(millisecondsDelay);
// it only works in WPF
Application.Current.Dispatcher.Invoke(() =>
{
// Do something on the UI thread.
});
});
You are looking at it wrong.
Click the button, it kicks off a timer with an interval of x seconds. When those are up it's eventhandler executes the task.
So what don't you want to happen.
While the x seconds are elapsing.?
While The task is executing?
If for instance it's you don't want the button to be clicked until delay and task are done. Disable it in the button click handler, and enable it on task completion.
If all you want is a five second delay prior to the task, then you should pass the start delay to the task and let it take care of it.
your application hangs because you are invoking the 5 second sleep/wait on the main UI thread. put the sleep/wait/whatever action in a separate thread (actually System.Windows.Forms.Timer should do that for you) and when it completes invoke the action that turns some control green. remember to check InvokeRequired. here's a short sample (SetText can be called from another thread, if it is the call will instead be invoked on the main UI thread where the textbox is on):
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
I took the sample from here (well worth a read!).
#eFloh in the post marked as answer said:
The Tick event may be executed on another thread that cannot modify
your gui, you can catch this ...
That is not what the docs say.
You are using a System.Windows.Forms.Timer in your example code.
That is a Forms.Timer.
According to the C# docs the Timer events are raised on the UI thread.
This Windows timer is designed for a single-threaded environment where
UI threads are used to perform processing. It requires that the user
code have a UI message pump available and always operate from the same
thread ...
Also see stackoverflow post here

MultiThreading inside Loop and Wait Threads WinForms and C#

I'm in trouble with this code. I'm using .Net (C#) with Winform Application.
I need to run RunProgram Method which has loop that make a call to a method named ListLoop.
In this function there is a forach that creates 1 thread for each element a list.
(Please Read the code before continue to read the description so you could understand what i'm talking about )
The problem is that if i dont make any control in the "for" (RunProgram Method) it starts (of course) 10 times The ListLoop Function.
So i would add in that "For" a code which wait that all Threads are terminated, so i can do Something and Then continue with the next loop.
I tried thread.join() but it freeze my UI application
(it's Application which inside has a WebControl Browser).
Even if i Try to play with returnThred and with thread.isAlive it still freezes UI.
If i hadn't the Multithread i'll dont stay here with those problems but it's the only good solution for my program i think.
Is there a simple solution for my code?
Update: Maybe it'snt clear my question.
I just want run the ListLoop X times but before start the next one i want wait that all threads are dead (That ones of the first call) so i can do some control and continue with the loop inside RunProgram.
Update2 I have this UI application which has a WebBrowser Control. I have a List of Links Object (each element of this class has string url and idHost =1 2 3 4...1 for google 2 for yahoo etc...)
I want make a loop where my program start a newTab (with Method AddTab(url) ) for each element of the list. When all links are opened (and so all the threads are deads and) i need to do something that count how many pages opened and who was the idHost save it and start another Loop with the list(This list take random element from a Bigger List)
Update 3 I just tried with BackGround Worker but i cant use it cause the WebKit that i'm using give COM error. Something for the Tasks.
Thanks
private void RunProgram()
{
List<Links> TheList = new List<Links>();
//Do something to Populate the List
List<System.Threading.Thread> returnThread = new List<.....>();
for(int i=0; i<10; i++)
{
returnThread=ListLoop(TheList);
// ???????????
// When Loop Method has finished and all threads stopped
// Do something
// Continue for the next Loop
}
}
private List<System.Threading.Thread> ListLoop(List<Links> list)
{
List<System.Threading.Thread> threading = new List<System.Threading.Thread>();
foreach (Links link in list)
{
Links tmp = new Links();
tmp = link;
var thread = new System.Threading.Thread(p =>
{
lock (l)
{
Action action = () =>
{
AddTab(tmp);
};
this.Invoke(action);
if (tmp.idHost == 1) //if IDhost == Google wait 5sec
{
System.Threading.Thread.Sleep(5000);
}
else
{
System.Threading.Thread.Sleep(2000);
}
}
});
threading.Add(thread);
thread.Start();
}
return threading;
}
If RunProgram is called from your main application, it will freeze your main form if it sleeps or waits for threads to terminate. You should run the RunProgram method in its own thread, so it can then create the worker threads, and then you can wait for the threads to complete in your for loop before starting new ones.
You could use AutoResetEvent to signal when threads are finished so you can simply wait on the AutoResetEvent before continuing the loop. The BackgroundWorker class may be a good class to look at for creating your threads as well.
I'm not sure if I understood your question properly, but:
You work asynchronously here... You can't wait in your code without stopping the GUI.
I think your solution will be to separate your function into 2 parts - The 1st one you just written, and the second one works after the threads are all dead.
For the second part (check the threads) I'd use either another thread (That waits until the threads are dead than continues to your code) or a Timer if you'd like to save threads and integrate easily into the main form
UPDATE:
Here is an example of how a blocking function that doesn't block the GUI thread:
using System.Windows.Forms;
using System.Threading;
using System;
namespace Threads
{
public partial class Form1 : Form
{
public event EventHandler OnSomethingFinishes;
public Form1()
{
InitializeComponent();
OnSomethingFinishes += new EventHandler(Form1_OnSomethingFinishes);
}
void Form1_OnSomethingFinishes(object sender, EventArgs e)
{
this.Invoke(new EventHandler(Form1_OnSomethingFinishesSafe), sender, e);
}
void Form1_OnSomethingFinishesSafe(object sender, EventArgs e)
{
this.Text = "Done!";
}
private void BlockingFunction(object a_oParameter)
{
// Do something that blocks
Thread.Sleep(2000);
if (OnSomethingFinishes != null)
OnSomethingFinishes(this, null);
}
private void button1_Click(object sender, EventArgs e)
{
Thread l_oThread = new Thread(BlockingFunction);
l_oThread.Start();
this.Text = "Please Wait...";
}
}
}
button1 starts the process. Notice that you have to invoke the function after the event is handled to move the control to the main GUI thread
Hope this helps

Categories