2

I have a simple app that read a database and then aftersome manipulation write the results on another one.

The first lines of code update the ui with a message for the user and an onscreen log, then is all wrapped inside a try/catch construct with usings and other try/catch annidated.

message.AppendText("** Message for the user that appear only after the try block's execution **\n");
message.ScrollToEnd();
try
{
    using(SqlConnection...)
    {
        business code
    }
}
catch
{
    bbbb...
}

In the end it works, but the ui is only updated when it finishes all. I can understand why what's inside the try must wait the end, but why the first lines don't affect the ui till the end of the successive block?

And how can I create more responsive ui? I first tried creating a thread for any connection (one has a timout of 5 seconds), and one for the businness code. Ok, it was overkill, but was experimenting. I had so much problems sharing the connections between threads and interacting with the main window's ui that abandoned the idea and rewrited all as described above.

Fehu
  • 381
  • 1
  • 3
  • 18
  • 4
    To keep the UI responsive, you need to move any lengthy code to a background thread. – crashmstr Mar 17 '14 at 15:33
  • It's easier to use compared to traditional thread? because my problem is that's too much complex for my and project's level. And anyway, why the code just before the try doesn't update the ui? :/ – Fehu Mar 17 '14 at 15:41
  • 1
    It doesn't depend on the `try`-`catch` block. When you put some code in an event handler like `OnClick...` this is executed on the UI thread and will block all UI stuff while the handler is executing. That is is why most programmers put long-running stuff in extra threads/background worker to keep the UI responsive. – Onur Mar 17 '14 at 15:48
  • As a last resort you may add the code described in this answer http://stackoverflow.com/a/4502200/1254743 whenever you have something to "update". But this will result in really really bad code – Onur Mar 17 '14 at 15:54

2 Answers2

4

People here have suggested creating a responsive UI. This is one way to do that. At the top of your code file, add:

using System.Threading;

Move all the stuff that takes a long time to a new method:

public void LoadStuff()
{
    // Do some stuff that takes a while here
}

Replace the original stuff with this code:

Thread callThread = new Thread(new ThreadStart(LoadStuff));
callThread.Start();

Now, anytime you need to update your UI from LoadStuff you have to encapsulate it (surround it) with this code. The reason for this is only the thread that creates the UI can modify it. So, we have to tell our new thread to refer back to the old thread to execute the code. Therefore, inside LoadStuff, after you compute a bunch of data, to update your UI use this:

this.Dispatcher.Invoke(new Action(() =>
{
    // Code to update UI here
}));

Like others have suggested, there are others ways to increase UI speed, and I was not the first to suggest using a different thread to compute. But I just wanted to show you a way to do it.

John Davis
  • 736
  • 6
  • 14
  • There's a way to wrap all the objects only one time in Dispatcher.Invoke and then reference directly in the following code? – Fehu Mar 17 '14 at 22:23
  • anyway thanks, now it works and is really cool to see it moving stuff around in realtime :) – Fehu Mar 17 '14 at 22:43
  • So you are proposing to bypass using a thread and just use Dispatcher.Invoke? I'm not sure I understand, Dispatcher.Invoke runs some code using the thread that created the UI. So this would defeat the purpose of using threads, but correct me if I misunderstood – John Davis Mar 17 '14 at 23:09
  • No, I'm very confused about this. Actually anytime that the code interact with the ui I must wrap that portion of code in Dispatcher.Invoke, so at the moment I have at least a dozen of Dispatcher.Invoke blocks (because I use a lot of try/catch). When I need the text value of a textbox in an if, it must be passed in another variable. It works perfectly, but the code now is very muddled. There's a way to make it simpler and cleaner to read? – Fehu Mar 18 '14 at 10:19
1

In addition to moving long-running processes off of the UI thread, there are some UI tricks that you can do to help make user interaction feel a little better. For example, if an action takes more than about 0.1 seconds, try fading in a message (e.g. "Loading...") to let the user know that there is something happening. Once you get the data back, fade this message back out.

You may also want to try animating the UI update to avoid the "stuttering" sensation.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315