Is there a way to see UI updates while debugging? - c#

At the moment I'm trying to debug some code in which I'm cheking for the visibility of items (with the .IsVisible() method for example). The problem is, when I'm jumping from one breakpoint to the next or jumping between lines, the data obviously changes, but the UI of the program doesn't seem to change at all. That makes it a bit difficult for me to tell if things are visible and I have to trust Visual Studio.
Is there a way I can make the UI update while debugging, so I can see the changes over there as well?

You have to force a synchronous re-render of the UI. You could define this extension method somewhere:
public static void SynchronouslyRedraw(this UIElement uiElement) {
uiElement.InvalidateVisual();
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => { })).Wait();
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => { })).Wait();
}
and call it on your Window after each breakpoint (using the immediate window, a breakpoint action, an additional line of code etc). It should synchronously re-render the Window in question:
this.SynchronouslyRedraw(); // assuming your breakpoint is in your `Window` class for example.
Note that this method works on any UIElement that is in the visual tree of a Window object.

The UI only updates when you give it a chance - that means not occupying the UI thread with other work (such as your event handler).
There isn't a simple way to do this in the debugger in WPF. In Windows Forms, you can just use Application.DoEvents();, but WPF requires you to await Dispatcher.Yield();, so you can't just execute it whenever you want. Both solve the same problem in much the same way - they give the message loop an opportunity to handle all the pending messages, and then go back to where you left off. Both also have the same weakness - they introduce an opportunity for reentrancy, so be careful.

Related

Catching cancel button click between two synchronous tasks

I have a list of tasks running and would like to show the progress in a (WinForms) form with a Cancel button.
I am aware, that there are several async options, but I have two restraints: The tasks must not run on a separate thread and the solution must be compatible with .NET 3.5 (it is an AddIn for a program, I have no access to).
It is fine, if one task finishes, before the cancellation comes into force. So I wonder, if there is some chance to check in synchronous code, if a mouse click on a button happened while having performed some task?
edit: This is the intended code:
foreach (IStep step in Steps)
{
if (Cancelled)
return;
step.Run();
ReportProgress(100.0 * completedWeight / totalWeight, step.Description);
completedWeight += step.Weight;
}
ReportProgress(100, "Completed");
So IStep contains a Run() method, and I am perfectly fine with completing a step before cancelling. I do not know how to catch mouse click on the Cancel button while executing some step to set Cancelled to true.
Obviously there is no "standard" solution here, so we have to think outside the box...
Say you have your application (AddIn or whatever, doesn't matter) and you can't control the loop from a button.
You read/write to the database.
On top of your loop, where it says:
if (Cancelled)
return;
We have to replace with:
If(CheckIsCancelled())
You have to find a way to make a button that can be clicked, either another form near the current one, but it must be able to run independently from the current form that is blocked by your loop.
Create a database parameter in some sort of Config/Util table.
E.g. CancelMyLoop - Bit
On that button click - set the parameter value to true.
And back to the method: CheckIsCancelled()
it will go in the db and read that value every time.
Downside is performance, but you want the impossible so you have to settle with a workaround like this...
You can create your own implementation, just giving you an idea.

How do I perform sequential BringIntoView calls in WPF?

We have a TreeView in our application with the following requirements:
When an item is added:
The newly-added item is scrolled into view
The parent of the newly added item is also scrolled into view.
If they are too far away to both be seen at the same time, the item takes precedence.
This seems easy, simply scroll the parent into view first, then scroll the child.
The problem is when you call it like this:
parent.BringIntoView();
child.BringIntoView();
...only the second one seems to have any effect. The first one is basically ignored.
I then tried wrapping the second call in a BeginInvoke() call like this:
parent.BringIntoView();
Dispatcher.BeginInvoke((Action)(() => {
child.BringIntoView();
}));
Which does work, but now you can visibly see the TreeView scroll twice; once for the parent, then a moment later, for the child, which just looks bad.
So how can I call BringIntoView back-to-back but without the double-refresh issue of using the dispatcher?
Try using the Loaded event instead of the dispatcher. According to this article, it's a perfect fit for situations like this:
... we initially implemented the Loaded event so that
it would fire just after the window was rendered, but before any input
was processed. We figured that if it was ready enough for input, it
was ready enough for load-time initialization. But then we started to
trigger animations off of the Loaded event, and saw the problem; for a
split second you’d see the content render without the animation, then
you’d see the animation start. You might not always notice it, but it
was especially noticeable when you run the app remotely.
So we moved
Loaded so that it now fires after layout and data binding have had a
chance to run, but just before the first render. (And note that if
you do anything in your Loaded event handler that invalidates layout,
it might be necessary to re-run it before rendering.)
In other words, on Loaded you have the most up to date information about the physical layout of the element, but it hasn't actually rendered yet, so you should be safe from any "screen flicker" issues.
EDIT: To answer your question in the comments, you can wire up events "local" to the current method using a closure, like this:
EventHandler handler = null;
handler = (sender, e) => {
this.LayoutUpdated -= handler; // only run once
child.BringIntoView();
};
this.LayoutUpdated += handler;
By defining the handler inside the method, you are able to access the method's local variables (child) from within. Very similar to the Dispatcher call.
I'm not sure if relying on LayoutUpdated is a good idea, actually. It happens quite often so it may end up firing sooner than you need. It happens twice for individual Width and Height settings, for example. Another one to look into is ScrollViewer.ScrollChanged. Or you could avoid BringIntoView altogether and try manually examining the element sizes to calculate where to scroll to.

Executing Code behind before Xaml Rendering - How to influence the sequence

I'm working on a Windows Phone App.
I have a very performance intensive method which takes several seconds until the operation is done.
When the method is called I want to show an animated loading symbol which is defined in the xaml of my view. When the operation is finished it should disappear. I set the loading symbol to visible in the first line of this method.In the last line I set the visibility to collapsed.
The problem is that at first the whole code behind will be executed. Unfortunately nothing is to be seen, because the the visibiliy is set to visible after the code behind operations are executed and in the same moment its set to collapsed.
Has anybody an idea how to solve this problem? Thanks so much in advance.
The problem you have is that you're calling your method on the main (UI) thread. This means that your method blocks the UI from refreshing, and also means that (as you noted) by the time the UI does refresh, you've already hidden the icon again.
What you need to do instead is call your method on a background thread (there are a number of ways to handle this). You will need to push the UI update to the UI thread (using Dispatcher.Invoke), but the rest of your method will run on a separate thread.
You'll also need to use a callback of some kind - maybe a custom event - so that your UI thread knows when the background thread is completed.
Without seeing the code its hard to say for sure but if you use the dispatcher to run you intensive code after the busy indicator is set this would allow the ui thread time to change before running the code.
An example
//This assumes you are binding in xaml to the isbusy and it implements INotifyPropertyChanged
IsBusy = true;
Dispatcher.BeginInvoke(()=>{ //...performance intense here
});
That being Said Dan Puzey is right. You should only run this logic on the UI thread if for some reason your need to. even then be wary of this as it makes for a poor ui experience.
One way you could accomplish this and still have your dispatcher fire off when you need would be to pass a copy of the dispatcher into the background.
ThreadPool.QueueUserWorkItem (d => {
//...performance intense here
Dispatcher dispatcher = d as Dispatcher;
if(dispatcher != null){
dispatcher.BeginInvoke()()=>{//...ui updates here }
}
}, Dispatcher.CurrentDispatcher);//make sure this is called from your UI thread or you may not end up with the correct dispatcher

Can I freeze my UI rendering while my form loads?

Is there any way I can pause all UI Update commands in Winforms?
Or I have a slight feeling I'm trying to go about this the completely wrong way, so is there another way around my problem: I basically load a saved state of a control, which loads new controls all over it. However I do some of this in the UI thread, and some of the data loading from another thread, which then fills the UI.
So the effect I have when it is loading is that the user can see a few of the controls appearing in one place, then moving to another place on the form, changing values, etc.
I'd like to get a loading screen instead of this and load the controls in the background. It's quite a large application and its not THAT important so redesigning my code isn't really an option.
Can I simply stop all Update() commands on a control while a method is executing?
You can use the SuspendLayout and ResumeLayout methods to wrap the setup of UI in one operation (without the update of the rendering).
Basically (assuming SomeMethod is in the form class):
private void SomeMethod()
{
this.SuspendLayout();
// all UI setup
this.ResumeLayout();
}
it really depends on your form logic, in general you should not overload the Load or Show method with too much things so that the form can be shown and drawn quickly and always look responsive.
in some cases it could help to use the SuspendLayout and ResumeLayout methods, see here:
Control.SuspendLayout Method

C# How To: Trying to call button twice in same class?

Did some searches here & on the 'net and haven't found a good answer yet. What I'm trying to do is call a button twice within the same class in C#.
Here's my scenario -
I have a form with a button that says "Go". When I click it the 1st time, it runs through some 'for' loops (non-stop) to display a color range. At the same time I set the button1.Text properties to "Stop". I would like to be able to click the button a 2nd time and when that happens I would like the program to stop. Basically a stop-and-go button. I know how to do it with 2 button events, but would like to utilize 1 button.
Right now the only way to end the program is the X button on the form.
I've tried different things and haven't had much luck so far so wanted to ask the gurus here how to do it.
BTW, this is a modification of a Head First Labs C# book exercise.
Thanks!
~Allen
You would need to use Multithreading (launch the process intensive code asynchronously in a separate thread), for instance, using the BackgroundWorker object in .NET 2+. This would be necessary because your UI will not respond to the user's click until the loop running in the Start method is completed. It is quite irrelevant if you use the same button or another one to toggle the process, because the processor is busy processing the loop.
The BackgroundWorker has a property called WorkerSupportsCancellation which needs to be true in this scenario. When the user clicks Stop you would invoke the CancelAsync method of the BackgroundWorker.
See MSDN for a good example. Also DreamInCode has a good tutorial which seems quite similar to your requirement.
Why not create two buttons, hide one when the other is visible? That should be a lot of easier to handle.
Or you can add a bool field to indicate which operation branch to execute.
One simple solution would be to add a boolean member to your form that is, e.g., true when the button says "Go" and false when the button says "Stop".
Then, in your button's event handler, check that boolean value. If the value is true, then start your operation and set the value to false when you change the button's text to say "stop". Vice-versa for the other case. :)
There are other techniques that I might prefer if this were production code, perhaps including considering the design of the form more carefully, but as this is clearly a learning exercise I believe that a simple boolean flag indicating the current state of the form is just what you're looking for.
Note that I would strongly discourage you from checking the value of the button text to determine what state the object is in. Whenever possible, as a general rule of good design, you want your visual state to be "decoupled" from your underlying object's state. That is to say, your visual widgets can depend on your underlying objects, but your underlying objects should not depend on your visual widgets. If you tested the text of the button, your underlying logic would depend on your visual state and that would violate this general rule.
If your problem is related to the fact that you can't cancel the operation while it's being performed, you'll want to look into using a BackgroundWorker to perform your long-running activity.
Another option would be to check the current text on your button to determine what to do:
void btnStartStop_Click(Object sender, EventArgs e)
{
if (btnStartStop.Text == "Go")
{
btnStartStop.Text = "Stop";
// Go code here
}
else
{
btnStartStop.Text = "Go";
// Stop code here
}
}
Are you getting your second button click event? Put a breakpoint in your click handler and run your code. When you click the second time, do you ever hit your breakpoint?
If your loop is running continuously, and it is in your button click handler, then your loop is running in the UI thread. You probably don't get to "see" the second button click until after the loop is completed. In addition to the branch code that you see above, try either inserting a DoEvents in your loop processing (this is a place where your loop will temporarly give up control so that messages can be processed). Or, (better) have a look at the backgroundworker class -- do most of your processing in a different thread, so that you UI can remain responsive to button clicks.
Cerebrus is right about using the Background Worker thread. However if you are doing a WPF app then it won't be able to update the UI directly. To get around this you can call Dispatcher.BeginInvoke on the main control/window.
Given code like:
Private Delegate Sub UpdateUIDelegate(<arguments>)
Private Sub CallUpdateUI(<arguments>)
control.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Background, New UpdateUIDelegate(AddressOf UpdateUI), <arguments>)
End Sub
Private Sub UpdateUI(<arguments>)
'update the UI
End Sub
You can call CallUpdateUI from the Background Worker thread and it will get the main thread to perform UpdateUI.
You could set the Tag property on the button to a boolean indicating whether the next action should be "Stop" or "Go", and reset it each time you click the button. It's an Object property, though, so you'll have to cast it to bool when you read it.

Categories

Resources