Is there anything special about '%' or "%"?

J

Jax

Custom control problem.
I'm modding a textbox so that it will always have a "%"
sign at the end of it.
I have overrided the Text property to account for the "%"
value within the textbox and have add BaseText to give
access to the baseText method too.
I have the text_changed event handler wired up to this
method, problem is that it works ONLY every other time.
The statement that works every other time is this:

string s = ResultOfOtherThings();
this.BaseText = s + "%";

In debugger I can see it doesn't add the "%";
I've tried:

s = s+"%";

But in the debugger s appears without the "%".
So therefore I ask is there anything "special" about '%'
or "%" because it's making little sense at best.
Full code follows:

public class PercentBox : System.Windows.Forms.TextBox
{
//Characters that are allowed to be typed into the box
private ArrayList allowedChars;

public ArrayList AllowedChars
{
get{return allowedChars;}
set{allowedChars = value;}
}
// my override of text
public override string Text
{
get
{
if(base.Text.Length>1)
{
return base.Text.Substring(0, base.Text.Length-1);
}
else
{
return "";
}
}
set{base.Text = value + "%";}
}
// to give access to the base still
public string BaseText
{
get{return base.Text;}
set{base.Text = value;}
}
public PercentBox()
{
base.Text = "%";
this.TextChanged += new EventHandler
(PercentBox_TextChanged);
this.KeyPress += new
System.Windows.Forms.KeyPressEventHandler
(PercentBox_KeyPress);
allowedChars = new ArrayList(10);
allowedChars.Add('0');
allowedChars.Add('1');
allowedChars.Add('2');
allowedChars.Add('3');
allowedChars.Add('4');
allowedChars.Add('5');
allowedChars.Add('6');
allowedChars.Add('7');
allowedChars.Add('8');
allowedChars.Add('9');
allowedChars.Add((char)8);
allowedChars.Add('.');
allowedChars.Add('%');
}

protected override void OnPaint(PaintEventArgs pe)
{
// TODO: Add custom paint code here

// Calling the base class OnPaint
base.OnPaint(pe);
}
private void PercentBox_TextChanged(object sender,
System.EventArgs e)
{
PercentBox pBox = (PercentBox) sender;
if(pBox.BaseText.Length>0)
{
// to make sure there only 1 % mark so the next if
//statement will work
string s = OnlyOneCharOfType(pBox.BaseText, '%');
if(s[s.Length-1] != '%')
{
// remove the eventhandler during the operation
this.TextChanged -= new EventHandler
(PercentBox_TextChanged);
string victim = pBox.BaseText;
// removes all '%' from victim
s = RemoveCharFromString(victim, '%');
// make sure there is only one decimal place
s = OnlyOneCharOfType(s, '.');
pBox.BaseText = s+"%";
this.TextChanged += new EventHandler
(PercentBox_TextChanged);
}
}
else
{
pBox.BaseText = "%";
}
}
private string OnlyOneCharOfType(string victim, char type)
{
bool found = false;
char[] result = new char[victim.Length];
int charCtr = 0;
foreach(char c in victim)
{
if(c == type)
{
if(found != true)
{
found = true;
result[charCtr] = c;
charCtr++;
}
else
{
continue;
}
}
else
{
result[charCtr] = c;
charCtr++;
}
}
StringBuilder sb = new StringBuilder();
foreach(char ch in result)
{
try
{
sb.Append(ch);
}
catch(Exception)
{
break;
}
}
string theResult = sb.ToString();
theResult = theResult.Trim();
return theResult;
}
private string RemoveCharFromString(string victim, char c)
{
char[] result = new char[victim.Length];
int charCtr = 0;
foreach(char ch in victim)
{
if(ch != c)
{
result[charCtr] = ch;
charCtr++;
}
}
StringBuilder sb = new StringBuilder();
foreach(char ch in result)
{
try
{
sb.Append(ch);
}
catch(Exception)
{
break;
}
}
string theResult = sb.ToString();
theResult = theResult.Trim();
return theResult;
}
/// <summary>
/// // Ensures that no letters can be added to a control
that has the key press event linked to this
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PercentBox_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
char c = e.KeyChar;
if(!ValidatePressEntry(c))
{
e.Handled = true;
}
}
/// <summary>
/// // Ensures that no letters can be
added to a control that has the key press event linked to
this save the '.' character for decimal places
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private bool ValidatePressEntry(char c)
{
bool bob = false;
foreach(char okChar in allowedChars)
{
if(okChar == c)
{
bob = true;
}
}
return bob;
}
}
 
M

Morten Wennevik

Not sure if I understand the problem. The control appears to work as it
should.
% is displayed at the end, no matter what text is entered or assigned to
PercentBox.Text.
% also shows up as expected in the debugger (Visual Studio .Net 2003)
 
J

Jax

Thanks for the reply Morten,
I'm runnning Visual Studio 2002 standard addition, I have
implemented an almost identical text box with a "£" infront
for currency values so I dont think there are any problems
in the setting up of the custom control.
The situation that i'm trying to prevent is the ability to
add numbers after the % mark, the code (as i'm sure you
understand) should correct this remove the "%" analyze the
remainder and then add the % to the end.
This is an example of me using it:

Percentbox value: %
change to: %5
result: 5
change to: 55
result: 55%
change to: 55%5
result: 555

I'm stepping through the debugger as well and on the line,
pBox.BaseText = s + "%";
the "%" does not get added to BaseText just string s is
added.
What on earth is going on?
Is there another/better/slightyworse way around this?

Thanks for the help.
jax
 
J

Jax

Fascinating, I fixed it.
pBox.BaseText = s;
pBox.BaseText += "%";

And it's fine.
????
any suggestions as to why this doesn't work on one line?

jax
 
M

Morten Wennevik

Ah, I got it, adding a number after the % will clear the % (entering % by
hand will also clear it!!!)

Well, you could store the "real" textbox as a private string

private string realNumber = "";

public override string Text
{
get
{
return realNumber;
}
set
{
realNumber = value; // make sure this is a valid number without %
base.Text = realNumber + "%";
}
}

Also, in the keypress event, set everything e.Handled = true;
and if validchar add the character to realNumber;
Note: you will have to handle arrow keys and deletion insertion, cursor
position

Or remove the ability to enter % and possibly prevent the user moving past
the % (this would require handling END and arrow keys, but I bet it would
look cool :p
 
J

Jax

Well i have got it sorted now by splitting the line

pBox.BaseText = s + "%";

into two lines
pBox.BaseText = s;
pBox.BaseText += "%"

like so.
No idea why that works and the top line didn't, it's gonna
confuse me for ages.

The hnadling I have for the key presses at the moment
allows you to specify in the arraylist allowedChars which
chars to allow through.
(bkspc has to be done in code though: allowedChars.Add
((char)8);)
That also allows all arrow keys and delete.
Only problem is that shift+number keys are going through
as well(!"£$%^&*()), fortunately I have exception handling
when I gather the results so it wont crash it.
And I could easily add some code to make sure shift isn't
being pressed.... i'll do it later.

Thanks for the feedback morten, i really appreciate it.

jax
 
G

Glen Jones MCSD

Jax,

Glad you got you new TextBox to work. I liked your idea, so I wrote my own.
I just though I would share my "Masked Edit Textbox" class example.
Source at end.
--
Glen Jones MCSD

public class PercentBox : System.Windows.Forms.TextBox
{
public PercentBox()
{
this.TextChanged += new EventHandler(PercentBox_TextChanged);
this.KeyPress += new KeyPressEventHandler(PercentBox_KeyPress);
}
// Shorten code length
private void Log( string strTemp )
{
System.Diagnostics.Debug.WriteLine( strTemp );
}

private void PercentBox_TextChanged(object sender, System.EventArgs e)
{
// Get the current string and position
string strTemp = this.Text;
int intPos = this.SelectionStart;

Log( "TextChanged [" + this.Name + "]" );
Log( " Text = '" + strTemp + "'" );
Log( " SelectionStart = " + intPos.ToString() );

// Now remove all % signs
strTemp = strTemp.Replace( "%", "" );

// Add the percet to the end
strTemp += "%";

// Is the new text the same as what was there
if ( strTemp == this.Text )
// Don't set it or it will prevent endlessly loop
return;

// Remove event so when we change it doesn't call again
this.TextChanged -= new EventHandler (PercentBox_TextChanged);

// Set the new string
this.Text = strTemp;

// Add this event back
this.TextChanged += new EventHandler (PercentBox_TextChanged);

// Was the caret in the last position
if ( intPos >= strTemp.Length )
// Reset the position before the % sign,
// since setting the text reset it.
this.SelectionStart = strTemp.Length - 1;
else
// Reset the position to were they were,
// since setting the text reset it.
this.SelectionStart = intPos;
}

private void PercentBox_KeyPress(object sender, KeyPressEventArgs e)
{
Log( "KeyPress [" + this.Name + "]" );
Log( " KeyChar = '" + e.KeyChar + "' " +
((int)e.KeyChar).ToString() );
Log( " Text = '" + this.Text + "'" );

// Are this key not allowed
if ( char.IsNumber( e.KeyChar ) == false &&
e.KeyChar != (char)8 &&
e.KeyChar != (char)'.' )
{
// Don't allow these keys
e.Handled = true;
return;
}

// Is this key a decimal
if ( e.KeyChar == (char)'.' )
{
// Do we already have a decimal in the string
if ( this.Text.IndexOf( '.' ) >= 0 )
{
// Don't allow these keys
e.Handled = true;
return;
}
}
}
}
 

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