form object

G

Guest

I am trying to a add a method to a helper class library I built that will
fade out the current form. My code is this:

public void fade(object currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

This works great if I go ahead and put it in my exit event on the form like
this:

int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
this.Opacity = i;
while(z<10000)
{
z++;
}
}
this.Close();

When I have it in my helper Class Library it tells me that "'object' does
not contain a definition for 'Opacity'". Am I doing this wrong or is this not
allowed?

Thank you for your help!
 
N

Nicholas Paldino [.NET/C# MVP]

James,

Well, you are passing in an object. In .NET, an object only has four
methods on it.

I assume you are coming from VB, which allows for calling
methods/properties without knowing the actual type. VB would then call the
property/method (slower than if it knew the type), not caring about the
type.

Needless to say, C# does not allow this. However, since you want to do
this on forms, you can easily change your type declaration to Form, like so:

public void fade(Form currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

And then it will compile.

Hope this helps.
 
G

Guest

Nicholas,

Yes, I am "coming from VB". I had tried doing it as (Form currentForm)
and when I compiled I would get this message: "The type or namespace name
'Form' could not be found (ar you missing a using directive or an assembly
reference?)".

James

Nicholas Paldino said:
James,

Well, you are passing in an object. In .NET, an object only has four
methods on it.

I assume you are coming from VB, which allows for calling
methods/properties without knowing the actual type. VB would then call the
property/method (slower than if it knew the type), not caring about the
type.

Needless to say, C# does not allow this. However, since you want to do
this on forms, you can easily change your type declaration to Form, like so:

public void fade(Form currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

And then it will compile.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

James said:
I am trying to a add a method to a helper class library I built that will
fade out the current form. My code is this:

public void fade(object currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

This works great if I go ahead and put it in my exit event on the form
like
this:

int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
this.Opacity = i;
while(z<10000)
{
z++;
}
}
this.Close();

When I have it in my helper Class Library it tells me that "'object' does
not contain a definition for 'Opacity'". Am I doing this wrong or is this
not
allowed?

Thank you for your help!
 
B

Bob Grommes

When you have the code pasted into your form event, "this" is a Form and
has Opacity.

The type "object" does not have an opacity property, hence your error.
You would have to unbox the form instance you pass in -- a costly and
unnecessary step.

Typically you would instead have this signature:

public static void Fade(Windows.Forms.Form currentForm)

By making it static in some class, call it MyUtils, you can call it from
any form like so:

MyUtils.Fade(this);

Alternately, you could make it a protected member of a parent form class
that your form inherits from, and eliminate passing the argument at all,
because the code internal to the routine could just use "this". So the
call would be:

this.Fade();

or simply,

Fade();

--Bob
 
B

Bob Grommes

Your utility class needs a reference to System.Windows.Forms, and it
needs a using directive for same, or else a fully qualified reference to
the System.Windows.Forms.Form class. ("using" in this context is
equivalent to "Imports" in VB.NET).

--Bob
 
N

Nicholas Paldino [.NET/C# MVP]

James,

When you do that, you will have to add a reference to
System.Windows.Forms.dll to your project (if it is not there already).

Then, at the top of your file, do this:

using System.Windows.Forms;


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

James said:
Nicholas,

Yes, I am "coming from VB". I had tried doing it as (Form currentForm)
and when I compiled I would get this message: "The type or namespace name
'Form' could not be found (ar you missing a using directive or an assembly
reference?)".

James

Nicholas Paldino said:
James,

Well, you are passing in an object. In .NET, an object only has four
methods on it.

I assume you are coming from VB, which allows for calling
methods/properties without knowing the actual type. VB would then call
the
property/method (slower than if it knew the type), not caring about the
type.

Needless to say, C# does not allow this. However, since you want to
do
this on forms, you can easily change your type declaration to Form, like
so:

public void fade(Form currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

And then it will compile.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

James said:
I am trying to a add a method to a helper class library I built that
will
fade out the current form. My code is this:

public void fade(object currentForm)
{
int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
while(z<10000)
{
z++;
}
}
}

This works great if I go ahead and put it in my exit event on the form
like
this:

int z = 0;
for(double i=1.0; i> 0; i-=.1)
{
this.Opacity = i;
while(z<10000)
{
z++;
}
}
this.Close();

When I have it in my helper Class Library it tells me that "'object'
does
not contain a definition for 'Opacity'". Am I doing this wrong or is
this
not
allowed?

Thank you for your help!
 
G

Guest

Bob & Nicholas,

Thank you for your help. I added the reference of System.Windows.Forms to
my helper class library and it works great! Just what I wanted to do! Now I
can call it from any form.

Thank you!

James
 
M

Marc Gravell

Two observations:

1: any static method should probably be thread-aware; when dealing with
forms, this means that it should probably test currentForm.InvokeRequired
and (if true) push the method onto the owning UI's thread; I'm pretty sure
(not 100%) that Opacity has thread affinity..

2: while(z<10000) {z++;}
I don't mean to be rude - just frank; this is quite possibly the worst way
of putting a delay into code:
* It will run at different speeds on different computers
* it might even get completely removed by an optimizing compiler (typically
only in release mode)
You don't want to Sleep(), as this will hang the UI thread (unless you spin
up a second thread that alternates between Sleep() [on its own thread] and
BeginInvoke() [on the form]); a timer would be the normal implementation?

Marc
 
C

Chris Dunaway

Bob said:
The type "object" does not have an opacity property, hence your error.
You would have to unbox the form instance you pass in -- a costly and
unnecessary step.

Correct me if I'm wrong, but boxing does not occur on references types.
Boxing refers to the conversion of a value type to a reference type
and unboxing is the conversion back. In this case, object is a
reference type already so no boxing occurs.

I took the OP code and ran it through Reflector and there are no box
instructions.
 
G

Guest

Marc,

Is Frank your alias???
Well, early on I thought about using a timer since a counter does not run
at the same speed on every cpu. I really don't care about burning up cpu
cycles on the local machine as they don't cost anything. I am somewhat
concerned about the differing speeds on the various local workstations.
But my first and foremost concern was to get the stupid thing to work and
since I didn't know how to reference the form and Bob and Nicholas told me
how, now I can refine the rest of the process. Now I just need to figure out
how to reference the timer.
Since I am new to C# (as Nicholas summized) solutions rather than
critiques are helpful. I already knew that I should use the timer, but I
still don't know how to.

James
 
G

Guest

Marc,

You said I shouldn't use sleep, but I couldn't figure out how to do it with
a time in my class library.

This is what I have done:

using System.Windows.Forms;
using System.Threading;


public void fade(Form currentForm)
{
for(double i=1.0; i> 0; i-=.1)
{
currentForm.Opacity = i;
Thread.Sleep(100);
}
}

Is this dangerous? It is working for me.

James
-------------------------------------------------------------------------------------
James said:
Marc,

Is Frank your alias???
Well, early on I thought about using a timer since a counter does not run
at the same speed on every cpu. I really don't care about burning up cpu
cycles on the local machine as they don't cost anything. I am somewhat
concerned about the differing speeds on the various local workstations.
But my first and foremost concern was to get the stupid thing to work and
since I didn't know how to reference the form and Bob and Nicholas told me
how, now I can refine the rest of the process. Now I just need to figure out
how to reference the timer.
Since I am new to C# (as Nicholas summized) solutions rather than
critiques are helpful. I already knew that I should use the timer, but I
still don't know how to.

James


Marc Gravell said:
Two observations:

1: any static method should probably be thread-aware; when dealing with
forms, this means that it should probably test currentForm.InvokeRequired
and (if true) push the method onto the owning UI's thread; I'm pretty sure
(not 100%) that Opacity has thread affinity..

2: while(z<10000) {z++;}
I don't mean to be rude - just frank; this is quite possibly the worst way
of putting a delay into code:
* It will run at different speeds on different computers
* it might even get completely removed by an optimizing compiler (typically
only in release mode)
You don't want to Sleep(), as this will hang the UI thread (unless you spin
up a second thread that alternates between Sleep() [on its own thread] and
BeginInvoke() [on the form]); a timer would be the normal implementation?

Marc
 
M

Marc Gravell

Fair point about solutions rather than critique; I'm hectic at the moment,
but I will dedicate a few mintes later on today to provide a timer based
solution for this.
The Sleep() solution addresses both CPU thrashing and the differing speeds
(on different CPUs), but it could still leave your UI feeling (slightly)
unresponsive; during all of those those 100ms back-to-back (so for a second)
you form will not really be available to process messages. Since this is
only a second this might not be a big problem; certainly a big improvement
on a loop.

Again - I will throw something together later today.

Marc
 
M

Marc Gravell

As promised, this is what I came up with over lunch...

Overview:
FormFader; externally only has a single static method (Fade); this checks to
see if a fade is already in progress, and if so aborts the old fade; it then
sets up a new object to represent the fade (and to use in the above check),
and starts running a method on a pool thread; this method fades by the set
"step" amount (slipping into the UI thread for a moment), then sleeps for an
interval (back on the pool thread); this gives the UI time (between steps)
to draw itself, respond to events, etc. When the opacity is "close enough"
it sets the opactiy to the target (to round out any floating point issues)
and exits the pool thread.

You could also add some kind of event or callback to indicate when the fade
has been completed...

Regards,

Marc


using System;
using System.Windows.Forms;
using System.Threading;
using System.Collections.Generic;
static class Program {

static void Main() {
using (Form f = new Form())
using (Button fadeIn = new Button())
using (Button fadeOut = new Button())
{
fadeIn.Dock = DockStyle.Left;
fadeOut.Dock = DockStyle.Right;
fadeIn.Text = "Fade In";
fadeOut.Text = "Fade Out";
f.Text = "Fade";
fadeIn.Click += delegate { FormFader.Fade(f, 1.0F, 0.1F,
100); };
fadeOut.Click += delegate { FormFader.Fade(f, 0.2F, 0.1F,
100); };
f.Controls.AddRange(new Control[] { fadeIn, fadeOut });
f.ShowDialog();
}
}
}
public class FormFader {

private readonly Form _form;
private readonly double _targetOpacity, _stepSize;
private readonly int _ticksPerStep;
private volatile bool IsAlive = true;
private FormFader(Form form, double targetOpacity, double stepSize, int
ticksPerStep) {
_form = form;
_targetOpacity = targetOpacity;
_stepSize = stepSize;
_ticksPerStep = ticksPerStep;
}
private void Enact(object state) {
// just to meet WaitCallback
Enact();
}
private void Enact() {
while(EnactStep()) {
//pause between steps
Thread.Sleep(_ticksPerStep);
}
lock (_fadingForms) {
_fadingForms.Remove(_form);
}
}
private bool EnactStep() {
bool result = false;
if (IsAlive) {
_form.Invoke((ThreadStart)delegate {
// now on UI thread
double delta = _form.Opacity - _targetOpacity;
if (Math.Abs(delta) <= _stepSize) {
_form.Opacity = _targetOpacity;
} else if (delta > 0) { // form's opacity is greater than
target
_form.Opacity -= _stepSize;
result = true; // keep going
} else {
_form.Opacity += _stepSize;
result = true; // keep going
}
});
}
return result;
}

private readonly static Dictionary<Form, FormFader> _fadingForms = new
Dictionary<Form, FormFader>();

public static void Fade(Form form, double targetOpacity, double
stepSize, int ticksPerStep) {
if (form == null) throw new ArgumentNullException("form");
if (stepSize <= 0.0F) throw new ArgumentException("stepSize");
FormFader newFader = new FormFader(form, targetOpacity, stepSize,
ticksPerStep);
lock (_fadingForms) {
FormFader oldFader;
if (_fadingForms.TryGetValue(form, out oldFader)) {
oldFader.IsAlive = false;
}
_fadingForms[form] = newFader;
}
ThreadPool.QueueUserWorkItem(newFader.Enact);
}
}
 
M

Marc Gravell

Correction: the _fadingForms.Remove(_form); code should read:

FormFader fader;
if (_fadingForms.TryGetValue(_form, out fader) &&
ReferenceEquals(this, fader)) {
_fadingForms.Remove(_form);
}

(all inside the lock)
This ensures that if two Fade() requests are made re the same form, then the
original request does not take the second fade-request out of the
dictionary.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top