|
Thank you, that is nearly what I already implemented to determine which controls to disable and which to leave responsive.
My problem is this: a control has UseWaitCursor set to true . It shows the WaitCursor, but user can still use it (click button, slide slider, whatever).
The same control has Enabled set to false . Now it is inaccessible, as intended, but doesn't show UseCursor any more. Instead the normal arrow cursor is shown, which is not intended.
How can I disable a control and show WaitCursor at the same time?
Ciao,
luker
|
|
|
|
|
I suppose you could intercept the OnClick and do nothing if the wait cursor is still applied, or similar status checking.
|
|
|
|
|
lukeer wrote: Are there any suggestions for
1. Disabling all controls except for "Cancel" button
2. Showing WaitCursor on all controls except for "Cancel" button
Luc Pattyn already suggested[^] a modal dialog which is impossible due to the information on screen that user needs to press the correct buttons as mentioned above.
Think about it this way: you are still using and displaying information to the user on the form. Thus, the form is not currently busy, thus it shouldn't show a Wait cursor. The wait cursor is meant for if your form is busy and unable to interact for a while. This is not the case here.
Disabling all unavailable controls is already a very good hint that the form is 'working' on something, but it also shows that the form is still valid and ready for use. If you set the wait cursor on your form (even if it's not on your cancel button) then I'd get confused as a user: the wait cursor tells me that the form is currently unresponsive, pending the completion of an operation. But it isn't.
My advise to you: don't use the Wait cursor for this. It's confusing.
|
|
|
|
|
My vote goes to MicroVirus' analysis here: you need to think about your design in the context of what people are socialized to in using Win Applications.
However, there are still things we don't know about the context of what you are doing that are quite important: you mention there's more than one "hardware" something that the app interacts with, and you imply that while the app may still be busy with some other hardware something(s), that one (more than one ?) other hardware something may have some controls presented in the app the user can interact with.
We don't know if there's an implicit sequence here ... access to hardware something #1 completes ... and then you interact with its controls while hardware something #2 is accessed ... and so on. Or, whether this whole thing is asynchronous, with hardware something #n going out for lunch whenever.
I suggest you think about a progress bar, or multiple progress bars here.
But "design" also depends on what you want your user to know in the context of your unique application: your specific application, perhaps, doesn't need to let the user know that the app is busy accessing hardware something(s) #1 ... #n ?
best, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
Thanks, Bill. I not only need to think about the design, but also about how to convince my customer that the reconsidred design is what he wants. For now, he wants the controls disabled and with WaitCursor.
For the important things we don't know yet:
There are several "hardware" somethings (devices). Let's call them Charlie, Augustus, Veruca, Violet and Mike.
The application shows several controls. One of them is some kind of "announcer" control. There is no 1-on-1 coupling between controls and devices.
User can start a sequence in which announcer says "Go to Chalie. Press the red button."
User then goes to "hardware" something called Chalie and presses the red button.
Announcer changes to "Go to Augustus. Press the red button."
User goes to Augustus and presses the red button.
Announcer changes to "Go to Veruca. Press the red button."
And so on until Mike's red button has been pressed.
While user is on his way pressing hardware buttons, there is no need for him to touch any of the application's controls (with the exception of "Cancel" button). Therefore controls shall be disabled and show the WaitCursor.
Since some controls (e.g. ListView) don't gray-out text when disabled, the additional WaitCursor would be a really great benefit. But it seems that disabling a control also disables its ability to show WaitCursor.
How can I disable a control and make it show WaitCursor at the same time?
Ciao,
luker
|
|
|
|
|
Kind of thinking "out of the box:" have you considered using a small animated gif file in a PictureBox to serve the same purpose as the WaitCursor ?
Check out: [^]
Just a thought, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
lukeer wrote: How can I disable a control and make it show WaitCursor at the same time?
Simple answer: you can't. I've experimented with this a little, just like you have.
What you are seeing here is base Windows functionality. If a parent uses the Wait Cursor, then all children are considered to be 'waiting' as well. A disabled control has no user interaction, so using a Wait Cursor on that doesn't work.
I've become quite convinced that there is no out-of-the-box way to achieve this. I'm guessing it's probably possible, but you're going to have to dig deep into the window procedure for the form and possibly for the child control as well. For a measly thing such as a cursor change, it's not worth the trouble and issues.
However, Bill has suggested an alternative, which I must admit sounds much better. I still think the Wait cursor idea is too much against common practice with what users are used to .
So, I suggest going with an alternative.
|
|
|
|
|
Was there a final resolution to this issue of having a disabled control AND a wait cursor at the same time?
Cheers,
Mike Fidler
|
|
|
|
|
Sadly enough, no.
I stayed with WaitCursor and enabled controls. In case of some user clicking anything, the software shows an error message.
Ciao,
luker
|
|
|
|
|
Goal: Have the WaitCursor over a disbled control
I experimented a little bit on a small C# form app.
Add a Panel to the form and make it the size of the Button you want to add.
Add the Button to the Panel and set Dock = Fill
(Panel obviously becomes the parent of the Button)
Disable the Button (Enabled = false)
Set Panel's UseWaitCursor = true
When the the app runs, the button will be disabled and
the WaitCursor will be visible over it.
Conclusion:
Use a parent panel to control WaitCursor visibility over a disabled control.
It's extra work but you can have what your customer wanted.
Cheers,
Mike Fidler
|
|
|
|
|
The question: given the variety of visual effects in Vista and Win7 possibly applied to Windows Forms in .NET, depending on system settings, themes, etc., can you algorithmically determine the precise boundaries of the display area of a Form where 'display area' is defined as exclusive of window borders, titlebar height, side-effects of visual settings like 'shadows' on Forms, etc.
And, oh yes, I don't wanna get near importing and using any API stuff !
Context: WinForm application, Visual Studio 2010 Pro, Win 7 Pro with all updates, 4 gigs of ram, older duo-core Intel CPU. GeForce 7100GS video card. Screen resolution: 1280x768
A concrete example:
only W7 visual effects enabled:
1. desktop composition
2. use visual styles on buttons and windows
In this software/hardware context: creating a "main" WinForm with a size set, in the design-time form editor, to, for example, 816,638, gets you this in the Designer.cs file:
this.ClientSize = new System.Drawing.Size(800, 600); Now, I add a second Form at run-time to my WinForm app, and I set its owner to be the "main form."
So: I write a re-size event-handler for this added, second, Form, so that I essentially keep it in the client display rectangle of the main Form: here's the way I (now) calculate the revised owner's client rectangle for "out of bounds detection:"
private Rectangle ownerClientRectangle;
private Rectangle currentClientRectangle;
private Rectangle intersectRectangle;
ownerClientRectangle = RectangleToScreen(RectangleToClient(this.Owner.Bounds));
ownerClientRectangle.Inflate(-14, -24);
ownerClientRectangle.Offset(0, 12);
currentClientRectangle = this.Bounds;
intersectRectangle = currentClientRectangle;
intersectRectangle.Intersect(ownerClientRectangle);
At this point I can be sure ... in this context only ... that if :
intersectRectangle != currentClientRectangle
Then the second Form is outside the boundaries of its owner ("main") Form, and I can 'do the right thing' to re-position it, which is simple.
The problem here is those magic numbers I am using for shrinking (negatively inflating), and off-setting the owner form's Bounds.
Of course I want to derive those inflation factors and offsets by calculation, not 'fiddlin around'
If those W7 graphic effects are turned off: the main Form that in the Designer.cs file is still written out as size 800,600: now appears, in the design-time property editor, with a size of : 808, 627 ... and, of course, the code for keeping the second Form in the boundaries of the first Form no longer works properly.
Appreciate any thoughts or advice !
thanks, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
modified on Sunday, September 4, 2011 10:08 PM
|
|
|
|
|
I have had similar problems, the thing (from what I have gathered) is that when you set the ClientSize property the form resizes then changes the ClientSize again based on the theme settings (i.e. title bar header sizes).
The outcome being your form keeps growing/shrinking (once) every time you show/hide.
The best workaround I have found is to set the form size instead.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|
Thanks for your response, Mehdi,
In this case, I am using the "shrunken" bounding box of the client area of the Owner Form to hit test when a second, "owned" (but not child) Form is moved, and re-positioning the second Form to always remain in the boundaries of the first form.
When I have time, I am going to experiment further with the differences between Form.Bounds, and the other Form-level 'area' properties under different conditions of configuring Win 7 visual effects, and see if I can't come up with some kind of compromise.
best, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
Cheers Bill,
I will try and investigate more (I gave up that feature last time!), let you know.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|
Hi Bill,
I found the following link while answering a question in the quick answers CustomerBorderForm, it might help you out.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|
Thanks, Mehdi, I look forward to studying this; haven't found time yet to go back and start turning on and off Win 7 window styles and examining their various effects on DisplayRectangle, ClientRectangle, Bounds, etc.
The last discussion forum item on that CodePlex project site[^] suggests to me there may be problems with that code on Win 7. But, I'll try it out, anyhow.
best, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
Hi experts,
an application I'm developing needs to tell user that it is busy. I therefore made most controls (excluding the "Cancel" button)
control.UseWaitCursor = true;
control.Enabled = false; When busy time ends, controls are set back to
control.Enabled = true;
control.UseWaitCursor = false; Now, cursor stays in WaitCursor representation until user moves the mouse by at least one pixel.
How can I make cursor change to normal immediately when resetting the underlying controls?
Ciao,
luker
|
|
|
|
|
It appears to me that all you have to do is to set the Focus on either the Form or a given control. This worked for me:
private void button2_Click(object sender, EventArgs e)
{
textBox1.Cursor = Cursors.Default;
button1.Cursor = Cursors.Default;
button2.Cursor = Cursors.Default;
this.Focus();
} good luck, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
I set the Form's cursor explicitly, so it looks like:
this.Cursor=Cursors.WaitCursor;
this.Cursor=Cursors.Default;
Of course, the cursor stuff isn't pretty, however you can easily make a disposable object for these purposes, so my code actually looks like:
using(new LP_WaitCursor(this)) {
}
where LP_WaitCursor holds a Cursor=Cursors.WaitCursor in its constructor, and a Cursor=Cursors.Default in its Dispose() method.
Side note: If the slow operation is bound to take more time, it should not happen on the main thread (which blocks the GUI), instead it should be another thread (maybe a BackgroundWorker) and then it is:
- either irrelevant to the user, hence no indication;
- or relevant, and then it deserves a progress bar and a cancel button.
|
|
|
|
|
Luc Pattyn wrote: Of course, the cursor stuff isn't pretty, however you can easily make a
disposable object for these purposes, so my code actually looks like:
using(new LP_WaitCursor(this)) {
}
where LP_WaitCursor holds a
Cursor=Cursors.WaitCursor in its constructor, and a
Cursor=Cursors.Default in its Dispose() method.
You know, I never thought of doing that. <smacks forehead>
|
|
|
|
|
Yes, it is elegant as it doesn't need explicit post-processing code.
I've learned this trick here on CP, many many years ago. Ever since, there is a lot of things I do with this pattern.
Now take care of that forehead, you will still need it.
|
|
|
|
|
Hi Luc,
That's a very interesting technique (I'd expect no less from you), and it leaves me curious to know if there's something about switching cursors that makes actually encapsulating them in a class, and disposing of them, as you've shown here, via 'using, best practice.
best, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
Not sure what you mean here Bill; what needed to be done took two statements, one upfront, and one in the back of the code; with the disposable object approach, all that remains visible is a single upfront statement with a clear intent, so you don't need to worry about the post-processing anymore.
I can't think of a better way, so I'd call it a best practice. And it doesn't apply just to cursors, you can do similar things with many objects you want to use-and-forget-about; either regular objects that just need to be disposed of (graphic objects such as Pens and Fonts, or database connections and commands), or your own objects that you want to give some post-processing actions. And the LP_WaitCursor example is the extreme incarnation: the object is almost empty, its main action happens at its life end.
|
|
|
|
|
Hi Luc,
First, I truly appreciate the time you took to comment further on this technique: I am already 'socialized' to wrapping things like 'StreamReaders' and such in 'Using' statements.
However, in this case, a simple need to change a cursor back to its default visual state, imho using a technique which involves creating a class seems to me like shooting a horsefly with a cannon
What's happening here is just another 'quirk' of Windows Forms: the need to set focus somewhere to 'provoke' the cursor to change visual state properly. A quirk I cannot even reproduce reliably (see example below).
Is it possible that I am 'off the planet' here, and you are talking about a DataBase cursor ... I hope not
In addition, if I understand it correctly, a class to be used in this pattern of Using/Dispose must inherit from IDisposable, a key fact, omitted here, the 'newbie' to .NET may not "get" too easily.
In VS Studio Pro 2010, compiling against .NET FrameWork 4.0 Client Profile, the following code in a button click handler:
using System.Threading;
private void button2_Click(object sender, EventArgs e)
{
button2.Cursor = Cursors.WaitCursor;
Thread.Sleep(10000);
button2.Cursor = Cursors.Default;
} Does reset the cursor properly after the call to the Thread.Sleep.
The "big picture," I am sure we both agree on is: any operation causing a noticeable delay should be handled by threading, so the UI stays responsive.
I look forward to further enlightenment !
best, Bill
"Is it a fact - or have I dreamt it - that, by means of electricity, the world of matter has become a great nerve, vibrating thousands of miles in a breathless point of time? Rather, the round globe is a vast head, a brain, instinct with intelligence!" - Nathanial Hawthorne, House of the Seven Gables
|
|
|
|
|
Bill, everything has been said, I don't know what to add. Here is the entire class:
using System;
using System.Windows.Forms;
namespace LP_Core {
public class LP_WaitCursor : IDisposable {
private Form form;
public LP_WaitCursor(Form form) {
this.form=form;
form.Cursor=Cursors.WaitCursor;
}
public void Dispose() {
form.Cursor=Cursors.Default;
}
}
}
It is independent of the actual WinForms application, and needs to be created only once as it belongs in a .NET programmer's toolbox IMO. I use it in every click handler (MenuItem, Button,...) that might take a noticeable amount of time. So there may be hundreds of using(new LP_WaitCursor(this)) statements in a single app, each one replacing a pair of Cursor=... statements.
Luc Pattyn [My Articles] Nil Volentibus Arduum
modified on Saturday, September 3, 2011 2:34 PM
|
|
|
|
|