double message box again

J

John Salerno

Ok, I'm having this problem again. The first I was able to use the
debugger to see that it was being called twice, so I fixed that. This
time, though, the debugger does not show it (MessageBox.Show) being
called twice, and sometimes it *doesn't* get called twice! So I don't
know why it's happening. Here's the code. I hope it looks ok, if not
I'll post it a different way.


namespace CharacterManager
{
public partial class frmCharacterManager : Form
{
private string incompatibleSelection = "Incompatible Selection";




#region Class validators

public bool IsBarbarian()
{
if (rdoBarbarian.Checked == true)
return true;

return false;
}

public bool IsBard()
{
if (rdoBard.Checked == true)
return true;

return false;
}

public bool IsCleric()
{
if (rdoCleric.Checked == true)
return true;

return false;
}

public bool IsDruid()
{
if (rdoDruid.Checked == true)
return true;

return false;
}

public bool IsFighter()
{
if (rdoFemale.Checked == true)
return true;

return false;
}

public bool IsMonk()
{
if (rdoMonk.Checked == true)
return true;

return false;
}

public bool IsPaladin()
{
if (rdoPaladin.Checked == true)
return true;

return false;
}

public bool IsRanger()
{
if (rdoRanger.Checked == true)
return true;

return false;
}

public bool IsRogue()
{
if (rdoRogue.Checked == true)
return true;

return false;
}

public bool IsSorcerer()
{
if (rdoSorcerer.Checked == true)
return true;

return false;
}

public bool IsWizard()
{
if (rdoWizard.Checked == true)
return true;

return false;
}
#endregion

#region Alignment validators

public bool IsLawful()
{
if (rdoLawfulGood.Checked == true || rdoLawfulNeutral.Checked == true
|| rdoLawfulEvil.Checked == true)
return true;

return false;
}

public bool IsChaotic()
{
if (rdoChaoticGood.Checked == true || rdoChaoticNeutral.Checked ==
true || rdoChaoticEvil.Checked == true)
return true;

return false;
}

public bool IsGood()
{
if (rdoLawfulGood.Checked == true || rdoNeutralGood.Checked == true
|| rdoChaoticGood.Checked == true)
return true;

return false;
}

public bool IsNeutral()
{
if (rdoLawfulNeutral.Checked == true || rdoNeutralGood.Checked ==
true || rdoTrueNeutral.Checked == true || rdoNeutralEvil.Checked == true
|| rdoChaoticNeutral.Checked == true)
return true;

return false;
}

public bool IsEvil()
{
if (rdoLawfulEvil.Checked == true || rdoNeutralEvil.Checked == true
|| rdoChaoticEvil.Checked == true)
return true;

return false;
}
#endregion

#region Race event handlers

private void rdoHuman_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoElf_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoDwarf_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoHalfElf_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoGnome_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoHalfling_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoHalfOrc_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}
#endregion

private void btnReorganizeAlignments_Click(object sender, EventArgs e)
{
Point p1;
Point p2;

p1 = rdoLawfulNeutral.Location;
p2 = rdoNeutralGood.Location;

rdoLawfulNeutral.Location = p2;
rdoNeutralGood.Location = p1;

p1 = rdoLawfulEvil.Location;
p2 = rdoChaoticGood.Location;

rdoLawfulEvil.Location = p2;
rdoChaoticGood.Location = p1;

p1 = rdoNeutralEvil.Location;
p2 = rdoChaoticNeutral.Location;

rdoNeutralEvil.Location = p2;
rdoChaoticNeutral.Location = p1;
}

public void SuggestClass()
{
if (chkSuggestedClass.Checked == true)
{
string noClass = "No Recommended Class";

if (rdoHuman.Checked == true)
{
string noHumanClass = "There is no suggested class for Humans.";
stsStatusLabel.Text = noHumanClass;
MessageBox.Show(noHumanClass, noClass);
}

if (rdoElf.Checked == true)
rdoWizard.Checked = true;

if (rdoDwarf.Checked == true)
rdoFighter.Checked = true;

if (rdoHalfElf.Checked == true)
{
string noHalfElfClass = "There is no recommended class for
Half-Elves.";
stsStatusLabel.Text = noHalfElfClass;
MessageBox.Show(noHalfElfClass, noClass);
}

if (rdoGnome.Checked == true)
rdoWizard.Checked = true;

if (rdoHalfling.Checked == true)
rdoRogue.Checked = true;

if (rdoHalfOrc.Checked == true)
rdoBarbarian.Checked = true;
}
}
}
}
 
P

Paul E Collins

John Salerno said:
public bool IsBarbarian()
[...]
public bool IsBard()
[...]
public bool IsCleric()
[...]
public bool IsDruid()
[...]

Hey, I know this isn't what you're asking, but have you considered
making your various character classes inherit from an abstract
Character? Then you could use the "is" operator and take advantage of
inheritance, rather than having masses of IsThis, IsThat type code.

P.
 
J

John Salerno

Paul said:
public bool IsBarbarian()
[...]
public bool IsBard()
[...]
public bool IsCleric()
[...]
public bool IsDruid()
[...]


Hey, I know this isn't what you're asking, but have you considered
making your various character classes inherit from an abstract
Character? Then you could use the "is" operator and take advantage of
inheritance, rather than having masses of IsThis, IsThat type code.

P.

Actually, I thought of this right from the beginning but didn't really
know how to do it. I love suggestions like this, because I'm always
trying to make everything as efficient and streamlined as possible.
Could you give an example of how I might implement the is operator for this?
 
S

SP

John Salerno said:
Ok, I'm having this problem again. The first I was able to use the
debugger to see that it was being called twice, so I fixed that. This
time, though, the debugger does not show it (MessageBox.Show) being called
twice, and sometimes it *doesn't* get called twice! So I don't know why
it's happening. Here's the code. I hope it looks ok, if not I'll post it a
different way.


namespace CharacterManager
{
public partial class frmCharacterManager : Form
{
private string incompatibleSelection = "Incompatible Selection";



#region Class validators

public bool IsBarbarian()
{
if (rdoBarbarian.Checked == true)
return true;

return false;
}

Some coding pointers. You do not have to use "== true" just
if(rdoBarbarian.Checked) is sufficient. You could also just use

return rdoBarbarian.Checked;
public bool IsLawful()
{
if (rdoLawfulGood.Checked == true || rdoLawfulNeutral.Checked == true ||
rdoLawfulEvil.Checked == true)
return true;

return false;
}

All these tests should really be separated out to some object.

Validator v = new Validator();
v.ChaoticGood = rdoChaoticGood.Checked;
v.ChaoticNeutral = rdoChaoticNeutral.Checked;

then you can ask the object

v.IsChaotic

and keep the complexities of the tests where they belong.
#region Race event handlers

private void rdoHuman_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoElf_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

You can use the same event handler for all the CheckChanged events as they
all do the same thing: SuggestClass()
private void btnReorganizeAlignments_Click(object sender, EventArgs e)
{
Point p1;
Point p2;

p1 = rdoLawfulNeutral.Location;
p2 = rdoNeutralGood.Location;

rdoLawfulNeutral.Location = p2;
rdoNeutralGood.Location = p1;

Never saw any code that related to you actual question!!

SP
 
J

John Salerno

SP said:
Some coding pointers. You do not have to use "== true" just
if(rdoBarbarian.Checked) is sufficient. You could also just use

return rdoBarbarian.Checked;

Ah, I knew that! Thanks for pointing that out!
All these tests should really be separated out to some object.

Validator v = new Validator();
v.ChaoticGood = rdoChaoticGood.Checked;
v.ChaoticNeutral = rdoChaoticNeutral.Checked;

then you can ask the object

v.IsChaotic

and keep the complexities of the tests where they belong.

I've been wanting to somehow separate these into a new class, or
something like that. But I don't quite follow your example. Are you
saying make a new class called Validator, and have those properties in it?
You can use the same event handler for all the CheckChanged events as they
all do the same thing: SuggestClass()

How do you mean?
Never saw any code that related to you actual question!!

Mainly it was the SuggestClass() method. Somehow the message box appears
twice when I have chkSuggestClass checked and I choose the rdoHuman button.
 
B

Bruce Wood

It looks to me as though you're having a problem I ran up against when
I first started programming WinForms with events.

The problem is that while reacting to an event you want to
programmatically change the state of the controls, but by doing so you
raise more events, which lead to unexpected and undesirable results.

I solved this problem by adding a boolean to each form:

private bool _updatingControls = false;

then, whenever I was manipulating controls in a way that might fire
events, I set the flag:

public void SuggestClass()
{
this._updatingControls = true;
try
{
... body of method here ...
}
finally
{
this._updatingControls = false;
}
}

and, finally, in each event handler, I coded:

private void rdoGnome_CheckedChanged(object sender,
EventArgs e)
{
if (!this._updatingControls)
{
SuggestClass();
}
}

that way, my event handlers don't react to events that are caused by
programmatic changes. The events are still raised, but the handlers
ignore them because the flag is set.
 
J

John Salerno

Bruce said:
It looks to me as though you're having a problem I ran up against when
I first started programming WinForms with events.

The problem is that while reacting to an event you want to
programmatically change the state of the controls, but by doing so you
raise more events, which lead to unexpected and undesirable results.

I solved this problem by adding a boolean to each form:

private bool _updatingControls = false;

then, whenever I was manipulating controls in a way that might fire
events, I set the flag:

public void SuggestClass()
{
this._updatingControls = true;
try
{
... body of method here ...
}
finally
{
this._updatingControls = false;
}
}

and, finally, in each event handler, I coded:

private void rdoGnome_CheckedChanged(object sender,
EventArgs e)
{
if (!this._updatingControls)
{
SuggestClass();
}
}

that way, my event handlers don't react to events that are caused by
programmatic changes. The events are still raised, but the handlers
ignore them because the flag is set.

Good idea. I was wondering how I might try something like this.
 
P

Paul E Collins

John Salerno said:
Could you give an example of how I might implement the
is operator for [distinguishing character types]?

Suppose you create an abstract (non-instantiable) base class along
these lines:

abstract class Character
{
public Character()
{
// common setup code for all character types
}

public virtual void CastSpell( ... )
{
// default implementation of casting a spell
}
}

Now all of the *real*, concrete character types can inherit from this,
e.g.

class Barbarian : Character { /* barbarian-specific code in this class
*/ }
class Wizard : Character { /* wizard-specific code in this class */ }

Using the "is" operator, you can then find out the specific type of a
character like this:

Character bob = new Barbarian();
// ...
if (bob is Wizard) { /* some code for if Bob was a wizard */ }

Generally, though, you won't want to test for a subtype explicitly.
(After all, that limits your code to working with the types it already
knows about.) What you can do is use "override" to make modifications
in each subclass. For example, CastSpell up there was declared
"virtual", which means that a subclass can replace it with its own
version, e.g.

class Wizard : Character
{
public override void CastSpell( ... )
{
// special spell-casting for wizards only, instead of the
default
}
}

If you're careful about what goes in the base class and what goes in
subclasses, you can then write your entire game based on the Character
class, and rely on overriding to make individual characters behave as
they should. Then you can add more character classes in the future
without even having to touch the game code, since the capabilities of
the characters are encapsulated inside their individual classes.

Hope that makes sense and isn't too patronising! You might well know a
lot of this stuff already.

P.
 
S

SP

John Salerno said:
SP wrote:

I've been wanting to somehow separate these into a new class, or something
like that. But I don't quite follow your example. Are you saying make a
new class called Validator, and have those properties in it?

Keep the form code as lean as possible. Without completely understanding
what you are trying to achieve it seems like you want to use an object to
create another object(s) based on the selection of the radio buttons. This
is called a Factory. The checked state of the radio buttons would represent
the parameters. There is also the issue that not all the radio button
selections are valid for creating an object. You could handle this by
validating before using the factory or the factory could do the validation
depending on the complexity of the validation.

private void rdo_CheckedChanged(object sender, EventArgs e)
{
Valiator v = new Validator();
v.ChaoticGood = rdoChaoticGood.Checked;
...

if(v.IsValid)
MyObject o = Factory.Make(v);
}
How do you mean?

You can hook up the CheckChanged on ALL of your radio button to the one
event handler. Instead of

private void rdoHuman_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

private void rdoElf_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

you just need

private void rdo_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

and then make this the handler for all the CheckChanged events. Goto the
radio button properties, select Events and then find the CheckChanged event.
Select rdo_CheckedChanged in the drop down.
Mainly it was the SuggestClass() method. Somehow the message box appears
twice when I have chkSuggestClass checked and I choose the rdoHuman
button.

I see you are using radio buttons and as they work in a group when you
select one it becomes checked while the others in the group become unchecked
but they all fire the CheckChanged event AFAIK. Now because you now have one
event handler for all the radio buttons then it is much easier to implement
Bruce Wood's suggestion also. Additionally you may only be wanting to fire
the event for the radio button that is now checked while ignoring the
unchecked buttons. Something like

if ((RadioButton)sender).Checked ....

HTH,

SP
 
J

John Salerno

Paul said:
Hope that makes sense and isn't too patronising! You might well know a
lot of this stuff already.

No, not at all! I love these kinds of suggestions, because I'm very new
to all of this. The funny thing is, I originally *did* start with a
Character class that the others would inherit from, but I just didn't
quite know how to do this. The thing that makes it seem not necessary
right now is basically I'm just messing with clicking radio buttons on a
form and figuring out how the Checked event works. There aren't really
instances of any characters (at least not yet).

But if I were to do the base class with subclasses, would that change
how I do the IsLawful, IsGood, etc. methods? I tried putting these in a
separate class, but I kept getting compile errors mentioning that the
rdo objects didn't have the right public access, etc. I made sure my
WinForm class was public, and I prefixed each object with its class, and
I referred to the Is methods with the new class name, but it just didn't
work, so I moved them all back to the Form class.
you can then write your entire game based on the Character
class, and rely on overriding to make individual characters behave as
they should.

Wow, believe it or not that statement has explained polymorphism to me
better than everything I've read so far. I knew what polymorphism *did*,
but now I clearly see how to use it! Just use Character all the time and
let the program figure out which is which.
 
J

John Salerno

SP said:
Keep the form code as lean as possible. Without completely understanding
what you are trying to achieve it seems like you want to use an object to
create another object(s) based on the selection of the radio buttons. This
is called a Factory. The checked state of the radio buttons would represent
the parameters. There is also the issue that not all the radio button
selections are valid for creating an object. You could handle this by
validating before using the factory or the factory could do the validation
depending on the complexity of the validation.

private void rdo_CheckedChanged(object sender, EventArgs e)
{
Valiator v = new Validator();
v.ChaoticGood = rdoChaoticGood.Checked;
...

if(v.IsValid)
MyObject o = Factory.Make(v);
}

Hmm, I haven't quite gotten to design patterns yet, so that might help.
But I still am unsure what v.ChaoticGood is referring to.
You can hook up the CheckChanged on ALL of your radio button to the one
event handler. Instead of
you just need

private void rdo_CheckedChanged(object sender, EventArgs e)
{
SuggestClass();
}

But will this affect *all* radio buttons on the form? There are more
that do not need to call SuggestClass.
 
S

SP

John Salerno said:
Hmm, I haven't quite gotten to design patterns yet, so that might help.

The sooner you start to use and understand design patterns the faster you
will progress. I programmed for years without anyone ever mentioning it.
But I still am unsure what v.ChaoticGood is referring to.

v.ChaoticGood would be a boolean property in your validation object. In a
nutshell you would be setting the various properties of your validator based
on the checked property of your radio buttons. Then you ask your validator
Is This Valid? All the logic like if(rdoXYX.Checked || rdoABC.Checked ....
would be encapsulated inside your validator where you would NOT be dealing
with your radio buttons at all but the private values in the validator set
from the public properties like ChaoticGood. Later on you might decide to
use a drop down instead of radio buttons and you would set the validator's
properties based on the drop down value. The validator would remain
unchanged.

public class Validator
{

private bool chaoticGood;
public bool ChaoticGood
{
set
{
this.chaoticGood = value;
}
}

public bool IsValid
{
get
{
if(this.chaoticGood || this.Evil....
return true;
....
}
}
But will this affect *all* radio buttons on the form? There are more that
do not need to call SuggestClass.

I said all because all of your event handlers were calling the same
SuggestClass method. But you are correct that you may need more than one
event handler.

SP
 

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