TextBox Array and Spaghetti Code

J

john.otten

Ok, so I am new to C# development and am working on a Windows Mobile 5
project with Visual Studio 2005.

Among the several forms that my application has is one that displays
11 TextBoxes. These TextBoxes represent 11 values of a 66 member
array of ints, and I only display 11 values at a time (I change the 11
values using a NumericUpDown box with a range from 1 to 6, so if the
UpDown box is set to 1, I display values at indexes 0..10 in the
array, if it is set to 1, I display values at indexes 11..21 in the
array, etc).

When I display the values on the form, I define a TextBox array as
follows:
TextBox[] arrTextBox = new TextBox[11] { textBox1, textBox2, ...
TextBox11 };
This way, I can initialize all the textboxes with pertinent values
from my 66 member array using a loop.

However, when I (and ultimately the user) wish to change a value in
one of the textboxes and store the new value in the 66 member array, I
am stuck creating a function to handle the TextChanged event for
*each* TextBox which creates 11 nearly identical functions
(contributing to spaghetti code). There must be a better way (using
only one function), but my lack of experience is not helping me find
it.

In the old days (C/C++ with MFC), each TextBox had a numerical value
associated with it, and (assuming the 11 textboxes were defined in
numerical order) I could figure out which textbox triggered the event
by subtracting the current textbox's numerical value from the first
textbox's numerical value. However, I do not see a corresponding way
to do this with C#. Something tells me that I might be able to do
this using the Name property of the TextBox by subtracting the values
of the substrings of the last two characters (textBox[01] &
textBox[04] becomes 04 - 01 = 3, which would be the correct index for
textBox4), but I am hoping there is a more elegant solution. Plus, I
do not know how I can get a handle to the textbox that caused the
event (which I assume is the sender object that is a parameter in the
Visual Studio generated function. Assuming that the sender object is
actually the TextBox that triggered the event, is there some way to
cast this sender object to become a TextBox?).

Any suggestions would be greatly appreciated!

John Otten
 
P

Peter Duniho

[...]
In the old days (C/C++ with MFC), each TextBox had a numerical value
associated with it, and (assuming the 11 textboxes were defined in
numerical order) I could figure out which textbox triggered the event
by subtracting the current textbox's numerical value from the first
textbox's numerical value. However, I do not see a corresponding way
to do this with C#. Something tells me that I might be able to do
this using the Name property of the TextBox by subtracting the values
of the substrings of the last two characters (textBox[01] &
textBox[04] becomes 04 - 01 = 3, which would be the correct index for
textBox4), but I am hoping there is a more elegant solution. Plus, I
do not know how I can get a handle to the textbox that caused the
event (which I assume is the sender object that is a parameter in the
Visual Studio generated function. Assuming that the sender object is
actually the TextBox that triggered the event, is there some way to
cast this sender object to become a TextBox?).

The sender of the event is indeed the TextBox itself, and you'd cast it to
a TextBox just as you'd cast any other reference.

As far as correlating a specific TextBox instance with your data, you
could take the sender reference and look to see which of the elements in
your 11-element array it is. But IMHO a better way is to just use the
Control.Tag property, to which you can assign any object.

Assign the integer index within the array to the appropriate TextBox
control's Tag property (C# will box the integer value into an Object
instance so that it can be referenced by the Tag property), and then when
you want to find that index later, having cast the sender instance to
TextBox (or Control, for that matter, if you don't really need the TextBox
members), you can retrieve the integer value by casting the Tag property
back to int.

For example, upon initialization:

for (int i = 0; i < arrTextBox.Length; i++)
{
arrTextBox.Tag = i;
}

Then in the event handler (using Validating as an example):

void ValidatingHandler(object sender, CancelEventArgs e)
{
int i = (int) ((Control)sender).Tag;
}

....where "i" then contains the index of the control within the original
array. You can then use that along with your NumericUpDown control to
determine which of the 66 actual values the event corresponds to.

Pete
 
B

Ben Voigt [C++ MVP]

Ok, so I am new to C# development and am working on a Windows Mobile 5
project with Visual Studio 2005.

Among the several forms that my application has is one that displays
11 TextBoxes. These TextBoxes represent 11 values of a 66 member
array of ints, and I only display 11 values at a time (I change the 11
values using a NumericUpDown box with a range from 1 to 6, so if the
UpDown box is set to 1, I display values at indexes 0..10 in the
array, if it is set to 1, I display values at indexes 11..21 in the
array, etc).

When I display the values on the form, I define a TextBox array as
follows:
TextBox[] arrTextBox = new TextBox[11] { textBox1, textBox2, ...
TextBox11 };
This way, I can initialize all the textboxes with pertinent values
from my 66 member array using a loop.

However, when I (and ultimately the user) wish to change a value in
one of the textboxes and store the new value in the 66 member array, I
am stuck creating a function to handle the TextChanged event for
*each* TextBox which creates 11 nearly identical functions
(contributing to spaghetti code). There must be a better way (using
only one function), but my lack of experience is not helping me find
it.

How about:

for( int i = 0; i < arrTextBox.Length; i++ )
{
int closure = i;
arrTextBox.TextChanged += delegate (object sender, EventArgs e) {
HandleTextChanged(closure, e); };
}
 
J

john.e.otten

[...]
In the old days (C/C++ with MFC), each TextBox had a numerical value
associated with it, and (assuming the 11 textboxes were defined in
numerical order) I could figure out which textbox triggered the event
by subtracting the current textbox's numerical value from the first
textbox's numerical value.  However, I do not see a corresponding way
to do this with C#.  Something tells me that I might be able to do
this using the Name property of the TextBox by subtracting the values
of the substrings of the last two characters (textBox[01] &
textBox[04] becomes 04 - 01 = 3, which would be the correct index for
textBox4), but I am hoping there is a more elegant solution. Plus, I
do not know how I can get a handle to the textbox that caused the
event (which I assume is the sender object that is a parameter in the
Visual Studio generated function.  Assuming that the sender object is
actually the TextBox that triggered the event, is there some way to
cast this sender object to become a TextBox?).

The sender of the event is indeed the TextBox itself, and you'd cast it to 
a TextBox just as you'd cast any other reference.

As far as correlating a specific TextBox instance with your data, you  
could take the sender reference and look to see which of the elements in  
your 11-element array it is.  But IMHO a better way is to just use the  
Control.Tag property, to which you can assign any object.

Assign the integer index within the array to the appropriate TextBox  
control's Tag property (C# will box the integer value into an Object  
instance so that it can be referenced by the Tag property), and then when  
you want to find that index later, having cast the sender instance to  
TextBox (or Control, for that matter, if you don't really need the TextBox 
members), you can retrieve the integer value by casting the Tag property  
back to int.

For example, upon initialization:

     for (int i = 0; i < arrTextBox.Length; i++)
     {
         arrTextBox.Tag = i;
     }

Then in the event handler (using Validating as an example):

     void ValidatingHandler(object sender, CancelEventArgs e)
     {
         int i = (int) ((Control)sender).Tag;
     }

...where "i" then contains the index of the control within the original  
array.  You can then use that along with your NumericUpDown control to  
determine which of the 66 actual values the event corresponds to.

Pete- Hide quoted text -

- Show quoted text -


Thanks for the suggestion! I'll give it a try. I must have attempted
to cast the sender object incorrectly as it raised a runtime error (I
was trying to do something like:
TextBox tmpTB = (TextBox) sender;
)
I'll try to cast on the fly as in your example to see if it works
better.

Thanks again!
John
 
J

john.e.otten

Ok, so I am new to C# development and am working on a Windows Mobile 5
project with Visual Studio 2005.
Among the several forms that my application has is one that displays
11 TextBoxes.  These TextBoxes represent 11 values of a 66 member
array of ints, and I only display 11 values at a time (I change the 11
values using a NumericUpDown box with a range from 1 to 6, so if the
UpDown box is set to 1, I display values at indexes 0..10 in the
array, if it is set to 1, I display values at indexes 11..21 in the
array, etc).
When I display the values on the form, I define a TextBox array as
follows:
TextBox[] arrTextBox = new TextBox[11] { textBox1, textBox2, ...
TextBox11 };
This way, I can initialize all the textboxes with pertinent values
from my 66 member array using a loop.
However, when I (and ultimately the user) wish to change a value in
one of the textboxes and store the new value in the 66 member array, I
am stuck creating a function to handle the TextChanged event for
*each* TextBox  which creates 11 nearly identical functions
(contributing to spaghetti code).  There must be a better way (using
only one function), but my lack of experience is not helping me find
it.

How about:

for( int i = 0; i < arrTextBox.Length; i++ )
{
    int closure = i;
    arrTextBox.TextChanged += delegate (object sender, EventArgs e) {
HandleTextChanged(closure, e); };



}- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -


Ok, if I understand your example, I need to create a function called:
HandleTextChanged(int closure, EventArgs e)
which will make the change to my array, using the "closure" variable
as the index into the span of 11 items:
arrayIndex = ((NumericUpDown.Value - 1) * 6) + closure; //
UpDown range is 1..6

The delegate portion of the example is basically defining a call to
this function for each instance of TextBox in the array and assigning
it to the TextChanged event. So, if arrTextBox[3] has its text
changed, it will trigger a call to HandleTextChange(3, e), correct?

I haven't poked into the EventArgs list yet, but I am assuming that
the modified text is found somewhere in this list (perhaps e[0]?).

Thanks for your help! I'll look into the delegate keyword give it a
try.
John
 
B

Ben Voigt [C++ MVP]

Ok, so I am new to C# development and am working on a Windows
Mobile 5 project with Visual Studio 2005.
Among the several forms that my application has is one that displays
11 TextBoxes. These TextBoxes represent 11 values of a 66 member
array of ints, and I only display 11 values at a time (I change the
11 values using a NumericUpDown box with a range from 1 to 6, so if
the UpDown box is set to 1, I display values at indexes 0..10 in the
array, if it is set to 1, I display values at indexes 11..21 in the
array, etc).
When I display the values on the form, I define a TextBox array as
follows:
TextBox[] arrTextBox = new TextBox[11] { textBox1, textBox2, ...
TextBox11 };
This way, I can initialize all the textboxes with pertinent values
from my 66 member array using a loop.
However, when I (and ultimately the user) wish to change a value in
one of the textboxes and store the new value in the 66 member
array, I am stuck creating a function to handle the TextChanged
event for *each* TextBox which creates 11 nearly identical functions
(contributing to spaghetti code). There must be a better way (using
only one function), but my lack of experience is not helping me find
it.

How about:

for( int i = 0; i < arrTextBox.Length; i++ )
{
int closure = i;
arrTextBox.TextChanged += delegate (object sender, EventArgs e) {
HandleTextChanged(closure, e); };



}- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -


Ok, if I understand your example, I need to create a function called:
HandleTextChanged(int closure, EventArgs e)
which will make the change to my array, using the "closure" variable
as the index into the span of 11 items:
arrayIndex = ((NumericUpDown.Value - 1) * 6) + closure; //
UpDown range is 1..6


Correct, except you might want a more suitable name for the first parameter,
rowIndex or something like that.
The delegate portion of the example is basically defining a call to
this function for each instance of TextBox in the array and assigning
it to the TextChanged event. So, if arrTextBox[3] has its text
changed, it will trigger a call to HandleTextChange(3, e), correct?
Exactly.


I haven't poked into the EventArgs list yet, but I am assuming that
the modified text is found somewhere in this list (perhaps e[0]?).

From your problem description I understood you already knew how to process
the TextChanged event singly.

For most events there's a specialization of EventArgs which carries
additional data. TextChanged uses EventArgs directly though.

You'll want to reference the textbox itself as you did above, the new text
can be referred to as "arrTextBox[rowIndex].Text".
 

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