My label text isn't updating properly in my 3.5 WPF MVVM app.
The do work part lasts long enough that you can see the waiting mouse pointer.
All I ever see is "Parsed" in the label, which is Bound to InfoText.
the Dispatcher and do work lines are in a Command's method.
Ideas?
The code
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
//do work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
private void SetInfoText(string text)
{
InfoText = text;
}
private string _infoText;
public string InfoText
{
get
{
return _infoText;
}
set
{
_infoText = value;
OnPropertyChanged("InfoText");
}
}
The only thing I can think of to explain it is that you're doing the work on the UI thread. This would prevent the dispatcher from redrawing until your work is done. The work being passed in Invoke is placed in the event queue, meaning it will be performed when idle.
The proper way to fix it is to do the work on a separate thread. If you're looking for workarounds though, look here.
Reference: MSDN
EDIT:
There are lots of ways to perform the work on another thread. Read up on BackgroundWorker, ThreadPool, Task Parallell Library, Threads. :)
Here's a really simple way to do the work in a background thread:
System.Threading.ThreadPool.QueueUserWorkItem( state =>
{
Dispatcher.Invoke((Action<string>)SetInfoText, "Start Parsing");
System.Threading.Thread.Sleep(5000); // Simulate work
Dispatcher.Invoke((Action<string>)SetInfoText, "Parsed");
});
Application.Current.Dispatcher.BeginInvoke(new Action(() => this.InfoText="Start Parsing"));
this works for me.
nevertheless i would put my long running process in a backgroundworker. so ui thread will not get blocked.
edit: if you do all your work in ui thread you should look at the overload for BeginInvoke - you can pass a DispatcherPriority. may be this helps too
Related
I am using SynchronizationContext as a means to synchronize to the GUI thread, for WinForms and WPF. Recently I ran into an issue with the old style async callbacks:
private void Button_Click(object sender, RoutedEventArgs e)
{
uiContext = SynchronizationContext.Current;
var cl = new TcpClient();
cl.BeginConnect("127.0.0.1", 22222, ConnectedCallback, null);
}
public void ConnectedCallback(IAsyncResult result)
{
if (SynchronizationContext.Current != uiContext)
uiContext.Post(x => MyUIOperation(), null);
else
MyUIOperation();
}
public void MyUIOperation()
{
Title = "Connected";
}
private SynchronizationContext uiContext;
This will throw an exception, because the SynchronizationContext.Current in the callback function is equal to the captured one, and therefore the UI operation is executed in the worker thread of the callback.
Using this exact same code in WinForms works as I had expected.
For now as a workaround, I am capturing the current ManagedThreadId instead and compare it in the callback. What is correct way to handle this?
Update:
I should add that I am modifying a very old existing class that currently uses the following construct:
if (control.InvokeRequired())
control.BeginInvoke(SomeFunction);
else
SomeFunction();
I am trying to remove the WinForms dependency, without having much impact on the clients of this class. The SomeFunction() is raising events, so if I just call uiContext.Send() or uiContext.Post() , the order of execution is changed since Post() will always queue the call, and Send() will always block.
Also, this is just a very small piece of code to show the root of my issue. In reality the function doing the Post() can be called from the main thread.
This is targeting .NET 4.0
It turned out, in .NET 4.5 the SynchronizationContext is in fact different in the callback function and the if statement would evaluate to true. This was a deliberate change, as discussed here
WPF 4.0 had a performance optimization where it would
frequently reuse the same instance of the
DispatcherSynchronizationContext when preparing the
ExecutionContext for invoking a DispatcherOperation. This
had observable impacts on behavior.
1) Some task-parallel implementations check the reference
equality of the SynchronizationContext to determine if the
completion can be inlined - a significant performance win.
2) But, the ExecutionContext would flow the
SynchronizationContext which could result in the same
instance of the DispatcherSynchronizationContext being the
current SynchronizationContext on two different threads.
The continuations would then be inlined, resulting in code
running on the wrong thread.
Because in my case, the call to MyUIOperation() function would need to
be called immediately if the ConnectedCallback function is called from
the main thread.
That means the call to MyUIOperation() would be a blocking call if the ConnectedCallback is invoked in the UI thread, as opposed to non-blocking if it is invoked from the another thread. This non-determinism could cause other problems down the road.
Just call Send instead. According to this article, the call to Send would just invoke the delegate directly if already in the UI thread.
Also, you could just do Dispatcher.Invoke() instead.
I'll try to be explicit. I create a Qt application, that has some buttons and a QTextEdit. Next i create a pthread. And offer the pointer to the MainWindow as the parameter. Something like this:
MainWindow w;
pthread_create(&rThread,NULL,treat,&w);
treat is the function that is executed when the thread is created. Now if i have a pushButton called myButton, and i do somthing like this inside the treat function:
void *treat(void *arg)
{
MainWindow *win = (MainWindow*)arg;
win->ui->myButton->setEnabled(false);
close(pthread_self());
}
It will work fine , and the myButton in my application will disable. However if i do something like this:
void *treat(void *arg)
{
MainWindow *win = (MainWindow*arg;
win->ui->editText->setText("random string");
close(pthread_self());
}
My application will crash with the following error:
QObject: Cannot create children for a parent that is in a different
thread. (Parent is QTextDocument(0x23af2e0), parent's thread is
QThread(0x209a290), current thread is QThread(0x7f7eec000af0) The
program has unexpectedly finished.
As i understand the Ui is living in the main thread, and probably is not accesible in the thread that i created , despite the fact that i offered the pointer of the main window to this thread. But why does disabling of the button work? I am very confused. The reason why i dint use the QThread is because our teacher told me not do it. I have to use pthreads. How could i apply such a change from the pthread to the editText ?
How could i send a signal from a pthread to the other thread in wich the Ui is "living". Thanks in advance guys.
Generally speaking, it's an error to call any of QObject (or derived classes') methods from a thread other than object->thread() - unless they are designed and documented to be thread-safe. There are a few methods in Qt proper that are explicitly documented as being thread safe, for example QCoreApplication::postEvent.
The behavior you're facing is due to accessing QWidget methods from the non-gui thread. It's undefined behavior, so some methods may crash, some won't, but even if they don't it's still undefined behavior that you can't count on. It may depend on the phase of the Moon, for all we know.
The only safe thing to do from another thread is to post an event to the object. When you use QMetaMethod::invoke or QMetaObject::invokeMethod on an object in another thread, Qt will internally post a QMetaCallEvent to the object. Since posting events is thread-safe (can be done from other threads), it's OK to do use either of those invoke methods from other threads. QObject::event() reacts to such events by executing the proper method call.
So, the only thing you can do from the other thread is:
QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));
Alas, this is bad design, since you're exposing MainWindow's internal details (like the ui pointer) to outside. What you should do instead is have a setEditText slot on the window:
MainWindow : public QWidget {
...
public:
Q_SLOT void setEditText(const QString & str) {
ui->editText->setText(str);
}
...
};
Then, from the other thread, you do:
QMetaObject::invokeMethod(win, "setEditText", Q_ARG(QString, "random string"));
I fully agree with Marek R's recommendation not to use pthreads when you have QThread available.
First of all mixing libraries when it is not necessary is bad habit. Qt provides QThread and very handy QtConcurrent.
Secondly this is bad design. Create some QObject which will handle yours calculations in thread and will emit signal when it should pass result to UI (main thread). Then create connection and Qt will handle rest of the stuff make it thread safe (by default it will queue connection if signal is passed between threads).
Your code with Qt concurrent:
void *treat(SomeClass *arg) {
arg->doStuff();
}
QtConcurrent::run(treat, someObject);
I'm new to RX but feel it should be able to provide a good solution to a task I wish to solve. After quite a bit of searching I still haven't found a solution.
I have a WPF application within which a control does some work in response to some mouse move events. I would like to reduce the frequency of the events, so that the handler gets called less frequently than is currently the case (as the user moves the mouse across the control). Ideally, what I want is to set up and subscribe to an observer. The observer should observe the mouse move events and call the client code with the most recent event and arguments after a particular time window has elapsed, say 0.2s. Being new to RX, I first replaced my original standard event hook-up with an observer as follows:
var mouseMove = Observable.FromEventPattern<MouseEventArgs>(myControl, "MouseMove");
mouseMove.Subscribe(args => myControl_MouseMove(args.Sender, args.EventArgs));
This seemed to work fine.
I then attempted to modify the observer to get the behaviour I described above. I tried using the Throttle() call and the Sample() call. These didn't produce the outcome I expected (or desire). In fact in certain cases using a particular overload of the Throttle/TimeSpan call killed my application dead, which still I don't understand.
This is an example of what I've tried:
var mouseMove = Observable.FromEventPattern<MouseEventArgs>(myControl, "MouseMove").Throttle(TimeSpan.FromSeconds(0.2));
mouseMove.Subscribe(args => myControl_MouseMove(args.Sender, args.EventArgs));
From reading, Throttle appears to swallow events until the frequency drops below a particular threshold (not quite what I expected), whereas I believe Sample samples the observed events at a regular interval? I would like the client code to be given the most recent event in a given time interval. If no events have been recorded in that interval, then the client should not be called.
Hope someone can help an RX newbie on this.
Oh, I also want to be kept informed of the (reduced frequency) mouse moves for the duration of the control's lifetime.
Max
I think you're on the right track with Sample - what, specifically, did this not do for you?
Example LINQPad snippet:
void Main()
{
var window = new Window();
window.Content = ctrl;
window.Show();
var mouseMove = Observable
.FromEventPattern<MouseEventArgs>(window, "MouseMove")
.Sample(TimeSpan.FromSeconds(0.2));
var disp = mouseMove.Subscribe(args => myControl_MouseMove(args.Sender, args.EventArgs));
window.Closed += (o,e) => disp.Dispose();
}
ItemsControl ctrl = new ItemsControl();
// Define other methods and classes here
private void myControl_MouseMove(object sender, MouseEventArgs args)
{
ctrl.Dispatcher.BeginInvoke((Action)(() => {ctrl.Items.Add(args.GetPosition(ctrl));}));
}
Let's say I have a several step process like during software installation for example.
Each step display a text box and wait for the user to click the "next" button.
The standard way to do it is to have a callback like this:
process
{
Dialog1() // Will call callback2 when closed
}
callback2()
{
Dialog2() // Will call callback3 when closed
}
callbak3()
{
Dialog3() // Will call callback4 when closed
}
This technique makes the code quite unreadable when there is a lot of steps as you have to
divide you process into each successive callback function (not to mention save
context from one to another).
What would be an easier to read way to do it ? Ideally the process should read like
this:
process()
{
Dialog1()
callback1() // stop method until closed
Dialog2()
callback2() // stop method until closed
Dialog3()
callback3() // stop method until closed
}
Problem with this is that you can't stop the UI thread. Any idea or work around would be very appreciated.
PS: this as to work in C or Objective C
ANSWER
So after having discovered coroutines thanks to Martin B I've found this page: https://stackoverflow.com/posts/4746722/edit and ended up using this code:
define coRoutineBegin static int state=0; switch(state) { case 0:
define yield do { state=__LINE__; return;
case __LINE__:; } while (0);
define coRoutineEnd }
void process()
{
coRoutineBegin
Dialog1()
yield
Dialog2()
yield
Dialog3()
yield
Dialog4()
yield
coRoutineEnd
}
You're looking for coroutines, which provide exactly the concept you're looking for: Yielding control from a function without exiting it. In essence, your code would look like this:
process()
{
Dialog1()
yield
Dialog2()
yield
Dialog3()
}
Unfortunately, coroutines aren't supported natively by C or Objective C and are hard to implement generically without resorting to ugly hacks. However, you may be able to take the concept as a starting point for a special-case construct for your situation.
You could use a Mutex or similar concept where the dialog is opened and run in a different thread.
Here is a post with an example I think is valid:
Synchronization/wait design for cross-thread event signaling (Obj-C)?
I don't quite understand the problem. Why doesn't showing a modal dialog work? Modal dialogs block until they are dismissed so your logic would look like:
Dialog1()
Dialog2()
Dialog3()
Another solution is to have your dialogs or callbacks or whatever send events. You then bind to those events. Your main logic would then look like this (sorry, I don't know how to do GUI examples in C/Objective-C, so I'll use Tcl/Tk because its highly readable):
bind $rootWindow <<Step1>> showDialog1
bind $rootWindow <<Step2>> showDialog2
bind $rootWidow <<Step3>> showDialog3
# kick off the first step
event generate $rootWindow <<Step1>>
The showDialogX functions would do whatever they need to do, then generate an event saying "I'm done, ready for the next step".
My code launches a background thread. The background thread makes changes and wants the UI in the main thread to update. The code that launches the thread then waits looks something like:
Thread fThread = new Thread(new ThreadStart(PerformSync));
fThread.IsBackground = true;
fThread.Start();
fThread.Join();
MessageBox.Show("Synchronization complete");
When the background wants to update the UI, it sets a StatusMessage and calls the code below:
static StatusMessage _statusMessage;
public delegate void AddStatusDelegate();
private void AddStatus()
{
AddStatusDelegate methodForUIThread = delegate
{
_statusMessageList.Add(_statusMessage);
};
this.Dispatcher.BeginInvoke(methodForUIThread, System.Windows.Threading.DispatcherPriority.Send);
}
_statusMessageList is an ObservableCollection that is the source for a ListBox.
The AddStatus method is called but the code on the main thread never executes - that is, _statusMessage is not added to _statusMessageList while the thread is executing. However, once it is complete (fThread.Join() returns), all the stacked up calls on the main thread are executed.
But, if I display a message box between the calls to fThread.Start() and fThread.Join(), then the status messages are updated properly.
What do I need to change so that the code in the main thread executes (UI updates) while waiting for the thread to terminate?
Thanks.
fThread.Join causes your main thread to block until the background thread finishes. As long as the main thread is blocked, the UI cannot be updated.
What you need to do is something like this (untested, but you should get the idea):
void someUiEventThatCausesTheBackgroundProcessingToStart() {
Thread fThread = new Thread(new ThreadStart(PerformSync));
fThread.IsBackground = true;
// disable some UI components here, so that the user cannot
// start the thread a second time
...
fThread.Start();
// *don't* call Thread.Join here, so that your main thread does not block!
}
void PerformSync() {
try {
// do your stuff here
...
} finally {
Dispatcher.Invoke(new Action(ProcessingDone));
}
}
void ProcessingDone() {
// re-enable the UI components
...
MessageBox.Show("Synchronization complete");
}
Of course, in WPF, disabling/enabling UI components is ideally done using some IsBusyProcessing dependency property which is bound with a trigger to the UI elements in question, but this is another story...
EDIT: As another option, you might want to check out the BackgroundWorker class, which contains ProgressChanged and RunWorkerCompleted events that automatically fire in the main thread.
fThread.IsBackground = true;
fThread.Start();
fThread.Join();
The call to Join() is blocking your main thread until the background thread finishes. So the UI thread can't do anything while the other thread is running. You need to not call Join(). If you need to do something on the main thread after the background thread finishes, find another way to do it.
EDIT: The reason it works if you display a message box between the call to Start and Join is because then the main thread is running the message loop for the message box, instead of being blocked at the Join call.
The BackgroundWorker is the right tool for this job. It's no more complicated than is absolutely necessary, gives you all of the hooks that you need for progress reporting, and there's plenty of information available (such as this answer) on how to use it.