views:

156

answers:

4

Let's say I have a C# program with a GUI, and the update/refresh/display of the GUI takes 0.2 seconds.

Say, while it is still computing the display process (within this 0.2 seconds), a new update request is given, so the current one is outdated. How can I make it stop doing this meaningless outdated work to start computing for the new request?

It might not be only about UI update too. Perhaps, for any function call, how can I make it so it will become "If another of the same call is issued, abandon the current work and go with the new data/situation instead"?

Thanks.

A: 

You're talking about some fairly advanced threading issues. Using the built-in system control structure, there's no way to prevent the message loop from completing any more than there is a method for interrupting (gracefully) another method.

Now, if this capability is very important to you, you COULD build all custom controls and within your control's painting code you could check (in a thread-safe manner, of course) a boolean value indicating whether or not painting should continue.

But if I can take a stab in the dark, I'm going to guess that you're not actually explicitly doing any multithreading. If this is the case, then the scenario that you describe can't ever actually happen, as the process of refreshing the GUI is going to complete before another one can begin (namely, this anonymous process you're describing that calls for another refresh or deems the current one stale). Because code on the same thread executes sequentially, there's really no opportunity for an unrelated piece of code to cause an update.

The semantics of how and when repaints take place (the difference between Invalidate() and Refresh(), and their respective impacts on this logic, for example) is a topic that's probably really not of interest to you. Just know that if you're...

  • Doing multithreading, then you'll have to implement your own code for checking whether or not the current operation should continue (for the UI, this means custom controls with this logic in the paint logic)
  • Not doing multithreading, then what you describe can never happen.

Hope this is helpful!

Adam Robinson
Thanks for the downvote without a comment. That's helpful.
Adam Robinson
A: 

One possible way is to start off a thread that updates the GUI and abort it and start another. This is generally not a recommended practice because of the horrible state of thread management in C# but you should be able to get around it without worrying.

public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                            Func<TControl, TResult> func)
    where TControl : Control
  {
    if (control.InvokeRequired)
      return (TResult)control.Invoke(func, control);
    else
      return func(control);
  }
}

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  Thread guiUpdateThread = null;
  public void BeginLongGuiUpdate(MyState state)
  {
    if (guiUpdateThread != null && guiUpdateThread.ThreadState != ThreadState.Stopped)
    {
      guiUpdateThread.Abort();
      guiUpdateThread.Join(); // wait for thread to abort
    }

    guiUpdateThread = new Thread(LongGuiUpdate);
    guiUpdateThread.Start(state);
  }

  private void LongGuiUpdate(object state)
  {
    MyState myState = state as MyState;
    // ...
    Thread.Sleep(200);
    this.InvokeEx(f => f.Text = myState.NewTitle);
    // ...
  }
}
Samuel
This will have no effect upon refreshing the GUI. The call to Invoke (which is required) executes the call on the main UI thread and simply blocks the execution of this thread until it completes. Terminating the waiting thread won't have any effect on the UI thread.
Adam Robinson
Yes it will, aborting will stop any further updates from that thread and starts a new cycle of updating.
Samuel
No, it doesn't. The updating isn't taking place on that thread (otherwise you'd see an exception for accessing the control handle from another thread). The update is taking place on the UI thread, and that thread is being blocked until completion. Stopping the blocked thread does nothing.
Adam Robinson
My assumption was that he was do a bunch of calculations and then updating a lot of the UI manually (not using databinding or such). And stopping the blocked thread prevents it from continuing to update the UI with out of data information.
Samuel
No, again, it won't. I'm not sure if you understand or not, but the actual update--the physical painting of the controls--takes place on the UI thread. You're aborting a DIFFERENT thread that's just waiting. It will have no effect on the UI thread.
Adam Robinson
Of course the actual painting of a control takes place on the UI thread, I do not believe that the OP wants to stop this. From what I gather, he is doing a lot of UI updates (which cause repainting) with data set A. Now part way through these updates, a new data set (B) comes in.
Samuel
Now that data set B has come in, data set A is no longer valid. I believe the OP wants to stop the updates that come from set A and start a new set of updates for set B.
Samuel
If you read the OP, this should become clear to you. "a new update request is given, so the current one is outdated"
Samuel
Exactly. His concern is that time is being taken to repaint the screen with the old data, and using this tactic will have zero effect on that.
Adam Robinson
I disagree, if he is doing 100 UI updates with each taking .02 seconds, if he stops them at 50 updates, it will have only taken 0.1 seconds and he can start a new 0.2 cycle.
Samuel
Disagree if you like, but his description says he wants to STOP the UI update within it, not stop the process of executing 100 distinct updates.
Adam Robinson
No, from the way he worded it, it suggests his "update" of the UI is a method which updates a bunch of properties on controls in his application.
Samuel
Nowhere does it indicate this. In fact, his broader request is to be able to stop a particular process from executing (in this case, I'm assuming a call to "Refresh") when it's no longer valid. He doesn't say anything at all to indicate that this is his scenario.
Adam Robinson
Unless he is using his own controls to do the data displaying, I *highly* doubt he is wanting to stop the painting instead of stopping a round of UI property updates.
Samuel
Well, considering that's exactly what he says, I'm not sure where you get your doubt from.
Adam Robinson
That's not what he says. He never mentioned painting at all, he said refresh of the UI, which would suggest updating the controls on a form.
Samuel
I guess we can sit here all day and say "No, it doesn't" and "Yes, it does" ;)
Adam Robinson
+1  A: 

Perhaps, for any function call, how can I make it so it will become "If another of the same call is issued, abandon the current work and go with the new data/situation instead"?

Why would you want that? You would lose all provability in your code. You would never be able to ensure a consistent state in your system. If you want to simulate it, just mess with the PC. Design a program that arbitrarily pushes the PC back to the top of any method that it is in. You would quickly see the system devolve.

JP Alioto
A: 

I don't knwo if this maps to what you need, but here goes. One way to achieve this kind of behavior is to reverse the problem and delay the actual rendering.

Any time you get a request or change, fire off a timer. Every request coming in will either start or restart the time. When the timer actually elapses, carry out the rendering. It does not do exactly what you describe, but it might actually do what you need in the end, which is not to render for each request because rendering takes too long.

If you do not have continuous requests, this works fairly well. Obviously, if you do, you never get anything displayed...

Denis Troller
There is a built-in mechanism in Windows Forms. Rather than calling Refresh(), calling Invalidate() will cause the form to refresh itself on the next iteration of the message loop (so it won't interrupt the rest of the code), but that isn't what he's describing.
Adam Robinson