 |
|
 |
Got my 5!
/ravi
|
|
|
|
 |
|
 |
I don't think this is quite done, but its certainly a great control so far!
|
|
|
|
 |
|
 |
This looks VERY COOL indeed. I will certainly have a closer look at it as soon as I get a moment free.
In the meantime: Is it possible to display some kind of loading animation (anigif for instance) on the loading curtain to mek the user aware that something is going on (mostly for relatively long loading periods)????
TIA,
Johnny J.
|
|
|
|
 |
|
 |
OH, one more thing:
I think I'll try using it for the main application form. When it starts up it draws the controls, and it takes quite some time. I would actually like to present my users with a screnshot of how it looks when it is DONE loading (which I cannot grab at the initial moment when it starts loading).
Is it possible to "pre-load" an image into the curtain and show that instead of a freshly taken screenshot?
TIA,
Johnny J.
|
|
|
|
 |
|
 |
You should add
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x80;
return cp;
}
}
to your CurtainForm to prevent it from being listed in the running programs list if the user hits alt-tab while a CurtainForm is created.
Maik
|
|
|
|
 |
|
 |
I think that native API function AnimateWindow is better than opacity/timer approach. It can be done with following code.
class AnimateWindowCurtain : CurtainAnimation {
public const int AW_HIDE = 0x10000;
public const int AW_ACTIVATE = 0x20000;
public const int AW_HOR_POSITIVE = 0x1;
public const int AW_HOR_NEGATIVE = 0x2;
public const int AW_SLIDE = 0x40000;
public const int AW_BLEND = 0x80000;
[DllImport("user32", SetLastError = true)]
public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);
public void Begin(CurtainForm curtain) {
}
public void Animate(CurtainForm curtain, int step, int totalSteps) {
AnimateWindow(curtain.Handle, 100, AW_HIDE | AW_BLEND);
curtain.Hide();
}
public void End(CurtainForm curtain) {
}
}
To make it working you must also tweak original code by removing (or make it condionally execute) lines manipulating opacity in Hide and Appear methods like this:
|
|
|
|
 |
|
 |
My implimentation is as follows:
private void showChart()
{
MT.CurtainForm myCurtain = new MT.CurtainForm();
myCurtain.Show(this);
chartClass ge = new chartClass(); //Actual name of class changed
ge.drawChart((System.Windows.Forms.Form)this);
myCurtain.Fade();
ge = null;
}
where "this" refers to a Windows form, showChart() is called on that form, and ge.drawChart() draws a chart on the form. The chart consists of text, lines, and about 65 rectangles. The rectangles are drawn with
SolidBrush grpBxBrush = new SolidBrush(Color.FromArgb(150,Color.SteelBlue))
graph.FillRectangle(grpBxBrush, nodeBox);
AS EACH OF THESE RECTANGLES ARE DRAWN HOWEVER, THEY MOMENTARILY FLICKER THROUGH THE SUPPOSEDLY TOTALLY OPAQUE CURTAIN.
I can lessen the problem to maybe one rectangle flickering through by drawing the rectangles with a solid colored brush as in
SolidBrush grpBxBrush = new SolidBrush(Color.SteelBlue)
rather than the partially transparent one. Also I can reduce the problem to no flicker by drawing only the text and lines and not the rectangles. Note however that there is even more text strings drawn than rectangles since each rectangle has a label and there are other text as well.
My only guess is that maybe the quantity of drawing is causing the flicker through but why that is escapes me. Any ideas?
|
|
|
|
 |
|
 |
Well, I got it to work when opening new forms, I call Show before creating the form, and Hide at the end of the form Load method. The new form is modal btw.
My problem is when I close the new form, I want to get the same effect when going back to the previous form, and I haven't been able to get it to work.
Any ideas how to make it work ?
|
|
|
|
 |
|
 |
Hi,
As I understand you want a kind of fading form (fade in and fade out). An easier way without using the curtain is to use the Opacity property of the form.
Fade in:
- in the form constructor: set Opacity to 0
- in the onload: create a timer
- in the timer hanlder method: increase Opacity
Fade out:
- in the form FormClosing event, if CloseReason == CloseReason.UserClosing, cancel the event and create a timer
- in the timer handler method: decrease Opacity
- finally close the form
If you want to use the curtain, its the form's parent that should show the curtain. But I don't feel like the curtain is the way to do it.
Regards,
Mathieu
|
|
|
|
 |
|
 |
Hi.
I really liked the demo that you have, but I can't quite get it to work in my code...
I want to hide an entire new form and not just a control on an already existing form.
I've created a static wrapper for the CurtainForm, and then from the parent form button click event:
CurtainHelper.CurrentCurtain = new CurtainForm();
SonForm sonForm = new SonForm();
CurtainHelper.CurrentCurtain.Show(sonForm);
sonForm.ShowDialog();
from what I understand, I should somewhere inside sonForm call CurtainHelper.CurrentCurtain.Hide() so that it'll show the son form again. My problem is that I've tried almost all the events in sonForm, but still the form updates itself in pieces.
|
|
|
|
 |
|
 |
Nevermind, got it to work just had to place the Hide command at the end of Load event
|
|
|
|
 |
|
 |
I really like this.
For info, I get an exception if, in the BindTo(..) method, Owner = null. In this case the the bindedControl_LocationChanged() event handler is triggered. This event handler passes m_bindedControl into another method, ComputeControlScreenBounds. However at this point m_bindedControl is null, so a null reference exception is thrown.
I'm not sure where would be the best place to catch this. I amended LocationChanged to:
private void bindedControl_LocationChanged(object sender, EventArgs e)
{
if (m_bindedControl != null)
{
Rectangle bounds = ComputeControlScreenBounds(m_bindedControl);
Left = bounds.X;
Top = bounds.Y;
Refresh();
}
}
which seemed to work.
|
|
|
|
 |
|
 |
Hi!
Thank you for your interest. Sure adding validation is always welcome! The check you added is right. However, a null owner is a somewhat strange and should be handled with care.
Actually the owner must be a form otherwise it will be null:
if (Owner == null)
{
Owner = control.TopLevelControl as Form;
BringToFront();
}
If another type of owner is needed, I would suggest modifying the BindTo method accordingly and avoid having a null owner.
Regards,
Mathieu
|
|
|
|
 |
|
 |
I was actually using it on the MdiClient of a form. I think the MdiClient is an unusual control. Your code works beautifully for hiding some ugly transitions when switching the Mdi view from maximized to cascaded, etc.
I'll have a look at modifying the BindTo method.
Cheers,
David
|
|
|
|
 |
|
 |
Fails if RightToLeft is changed on the main form, while curtained. Probably this causes the main form to come to the top, but have not looked into this in detail. Shame it does not work as 'hot-swapping' the culture involves a lot of redrawing and sometimes a RightToLeft change. It's a classic case where this technique would be of great use.
|
|
|
|
 |
|
 |
Thank you. I'll look at it.
Regards,
Mathieu
|
|
|
|
 |
|
 |
Mathieu,
unfortunately the problem still persists. I've managed to narrow it down to the event when the workstation is getting unlocked.
In my case I have a main app which embeds another app in itself and the child app is the one protected by the curtain. The main app tracks all resize events and forces the child to resize accordingly.
It appears that resize messages are pumped before the workstation is unlocked completely, meaning some windows haven't been redrawn and graphics object may fail.
The workaround I've come up with involves tracking the workstation's lock and unlock events. The idea is gotten from .Net Security Blog[^]
The main changes are as follows:
protected virtual void OnSessionLock()
{
this.locked = true;
}
protected virtual void OnSessionUnlock()
{
Thread.Sleep(1000);
this.locked = false;
}
private void DisplayStillImage()
{
if (this.locked)
return;
try
{
this.TakeScreenSnapshot();
}
catch
{
if (this.m_screenGraphics != null)
{
this.m_screenGraphics.Dispose();
}
...
}
private void TakeScreenSnapshot()
{
if (this.locked)
return;
if (this.m_screenGraphics != null)...
}
If you interested I can email the whole lot to you...
|
|
|
|
 |
|
 |
Hi,
Very subtle bug! Thank you for finding it. If you send me your code, I'll post it here for everyone. Good work.
Regards,
Mathieu
|
|
|
|
 |
|
 |
Could you please explain a bit more how exactly the AutoClose feature works?
I'm "paranoid" on cleaning up resources after using it,so:
I'm doing a new Curtain whenever I want to "hide" the updates.
And then do Curtain.fade at the end.
But does it clean up and "dispose" after finishing the fade?
thanks,
Carlos
|
|
|
|
 |
|
 |
Hi,
CarlosMMartins wrote: But does it clean up and "dispose" after finishing the fade?
Actually, no. And I agree with you that this is somewhat non-intuitive when you want a new curtain object at each fade. The curtain is a form and needs to be closed explicitly in order to dispose its resources. An AutoCloseCurtain object will automatically close its curtain when out of scope. The problem is that it doesn’t wait until the fade is finished. So its use is limited in your case.
Personally I prefer reusing the same curtain when hiding the same region to avoid the setup task (resizing, creating buffers…). So the curtain object is a member variable and I can encapsulate it in an AutoCloseCurtain object in order to close it automatically. I would recommend using this technique when possible.
If you still want or need to use a different curtain object each time, you could add an AutoCloseAfterFade attribute to the curtain. I may add it in the next release.
Regards,
Mathieu
|
|
|
|
 |
|
 |
Thanks for your reply.
I ended up tweaking it a bit (I was getting a form with a "title bar" when trying to cover a user control I wanted to "curtain").
Yes, I understood your intended use after going through your code - and I agree with you.
However, for this particular case, as it's a complete custom graphical application, with dozens of userdrawn controls, which can be updated concurrently and/or at different times, I prefer to have each object in charge of it's own "curtain" and have it all self-contained.
For this scenario, I don't mind wasting the "new" setup phase each time it begins a curtain effect - it's just a few milliseconds.
I ended up creating 2 different objects.
One, for user drawn controls, uses the same idea, but it just displays a alpha blended "capture" over the new screen. (It does the same effect but without actually creating a new form) - this works fine for objects that are completely drawn by the user.
However, for container controls, that can have any number of "unknown" objects in there I had no way to render it all to an "off-screen" bitmap. So, I had to use your method of putting a fake form over it, and tweak it so it wouldn't show any title, borders, etc. as I'm never using it to cover a complete form, just user controls. That's my second UserDrawn object that is based on the "Panel" object and can contain other controls.
|
|
|
|
 |
|
 |
So (I'm interested to know!) what will you use to close the curtain after the fade? A new AutoCloseAfterFade attribute?
Mathieu
|
|
|
|
 |
|
 |
Basically it's embedded on a new "CurtainPanel" control I created.
It's based on the regular "Panel", allowing you to add new objects to it - but it implements a new BackgroundPaint method (drawing some nice custom borders and titlebar. It's to be used as smaller "windows" containing other objects inside the main form.
It implements the beginUpdate/endUpdate that trigger your code - however:
1) the begin update creates the new curtain form (aborting and disposing if it was already in progress)
2) the end update, begins the fade out, and when it finishes, the timer signals the curtain form to be closed and dispose all the stuff (form, bitmap, timer).
|
|
|
|
 |
|
 |
excellent
|
|
|
|
 |
|
 |
The interesting thing is how to steal the focus and how to copy the screen.
It's very handy when you want to lock the UI when doing some background work in another thread(such as Calling a WebService).
It also reminds me some articles about how to make a transparent panel in C#.
Good work!
|
|
|
|
 |