Check every TextBox for letters - c#

Lets assume I have 5 TextBoxes like this:
textBox_Box1
textBox_Box2
textBox_Box3
textBox_Box4
textBox_Box5
And I have a function that checks if the TextBox contains only letters, like this:
public static bool OnlyLetters(string s)
{
foreach (char c in s)
{
if (!Char.IsLetter(c))
return false;
}
return true;
}
Is there an efficient way to check every textBox with this function? I do not want to write it in this style of course:
OnlyLetters(textBox_Box1.Text);
OnlyLetters(textBox_Box2.Text);
OnlyLetters(textBox_Box3.Text);
OnlyLetters(textBox_Box4.Text);
OnlyLetters(textBox_Box5.Text);
I would prefer to check it in a loop, but I do not know how to realize it at that point.

You could create an array of your TextBoxes:
private TextBox[] textBoxes = {
textBox_Box1,
textBox_Box2,
textBox_Box3,
textBox_Box4,
textBox_Box5
};
Then you can access it in a loop:
foreach (TextBox txt in textBoxes)
{
if (!OnlyLetters(txt.Text))
{
// Do something
}
}

One way would be to put all your text boxes in some sort of container and then loop through the children of the container (which will be text boxes) and preform a check on each. That way, you can add and remove text boxes from the container as needed without modifying your code.
When you are looping through the text box container, check to see if the child you are on is in fact a text box, then preform a cast on it so you may access it's text property.
I do not know which framework you are using, so I cannot provide a code sample.

You said you would like to check it in a 'Loop'. I don't know what GUI framework you are using so the types might be wrong, but you could do something like the following:
List<TextBox> textBoxes = new List<TextBox>();
// Add all your textBoxes to the list here
Then use a loop on the list of textBoxes whenever you want to check their contents. If it's a mobile platform you should probably see if it's possible to limit the type of keyboard shown, and on iOS you can automatically have the UI components added to the list so you don't have to manually write the code. Hope this helps a bit!

Related

Change "text" property of all buttons on form incrementally

I have created a soundboard in Visual C# where I click buttons and it plays an MP3 file. I currently have buttons named SBut_01 to SBut_x appropriately.
I store paths to the MP3 files that are being associated to these buttons in an xml file, which is fed in on startup and all "captions" for the corresponding buttons (which are extracted from the path for each key) are stored in an array named ButtonCapts[x].
An example of something that could be in ButtonCapts[1] would be Foo stored as a string.
Originally when I created this soundboard, I manually specified each button's caption using a method I named AssignButtonCaptions. Which worked crudely like so:
public void AssignButtonCaptions{
SBut_01.Text = ButtonCapts[1];
SBut_02.Text = ButtonCapts[2];
...
}
However, as this soundboard expands in scope this is becoming a very large section of hardcode, so I would like to automate this as much as possible.
I've thought that I could probably use a foreach loop in the instance of ButtonCapts[], but I don't at present know a way to loop through all of my SBut_xx buttons. Is it possible to detect all buttons on a form that are prefixed by SBut_ and iterate through them from 1 to x?
It would be great if something like below could be accomplished. Please note that I have assumed that each button has been put in an array named SButList as an example of what I'm trying to accomplish. I understand there is no way this code would work in its current form and am not even sure if objects such as buttons could be stored in such a way:
//Some kind of method to put all buttons prefixed with SBut_ in to an array named ButtonList here
//Then, iterate through all of the buttons and assign the captions
int i = 1;
foreach (button SBut in ButtonList)
{
SBut.Text = ButtonCapts[i];
i++;
}
Is this possible?
Thanks
Ok, so I've figured this out with some help from Anu6is. I'll document what I found so that it may help others.
Turns out that you can easily extract all controls in a form by using the following to accomplish this:
var myButtons in Controls.OfType<Buttons>().Where(button => button.Name.Contains("Something"))
The issue I was having was that I needed to iterate through each parent directory, as my buttons were inside of a Group Box, which was in turn inside of one of many Tab Pages within a Tab Control object. I just did a quick foreach loop to iterate through all of these tabs and group boxes in order to resolve this.
My new working code looks like this, which in my opinion is much better:
public void AssignButtonCaptions()
{
foreach (TabPage Page in tabControl1.TabPages)
{
foreach(GroupBox ButtonContainer in Page.Controls.OfType<GroupBox>())
{
foreach (var SButton in ButtonContainer.Controls.OfType<Button>().Where(button => button.Name.Contains("SBut")))
{
int ButtonNum = Int32.Parse(SButton.Name.Split('_')[1]);
SButton.Text = ButtonCapts[ButtonNum];
}
}
}
}

Issue while iterating through User Controls in a Windows Form

I am facing an issue while running through all the User Controls in my Windows form.
I am creating a Windows Form that has the following features:
The Main form has 3 User Controls embedded in it
The Main form also has a combo box. Selecting a particular value in the Combo box will bring the corresponding User Control to the front.
Each User Control has two Check boxes as well as two Combo boxes.
The User can summon each User Control through the Main Form's combo box and check the check boxes and/or modify the combo boxes inside each User Control
Once this is done, there is a button, which on being pressed, executes the following code. This code is supposed to check which check boxes have been checked from every User Control, and execute some functionality :
private void button1_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
if (c is UserControl)
{
foreach (Control ctl in c.Controls)
{
if (ctl is CheckBox && (ctl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
}
}
}
//Some other code after this
}
Here, I have included a Text Box called "Indicator" that shows whether the compiler has entered a particular "for" loop or "if" block. And I'm observing that the innermost "if" alone is not getting executed.
Could someone point out why exactly this is happening?
You need a recursive algorithm,
void ProcessControls(Control ctrlContainer)
{
foreach (Control ctrl in ctrlContainer.Controls)
{
if (ctrl is CheckBox && (ctrl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
if (ctrl.HasChildren)
ProcessControls(ctrl);
}
}
I do think you might be better off adding some functionality to your user control so it can describe the state of its own checkboxes rather than going digging inside it to find it and do logic. Generally in OO programming, when we encapsulate things within a class, we also provide general purpose accessors "visible to the outside" to describe the internal state of affairs, rather than letting external code interests go poking around inside class to find out what they want
At some point in time you've added these usercontrols to the form either directly in the designer, or programmatically. In the first case they will have their own name:
var u1 = usercontrol1.GetCheckboxStateArray();
var u2 = usercontrol2.GetCheckboxStateArray();
Etc
Or maybe you added them programmatically, in which case it would make sense to keep track of them in a list as you're adding them:
protected List<UserControl> _ucList = new List<UserControl>();
...
foreach(var result in somedatabasequery){
var uc = new UserControl(result.Whatever);
this.Controls.Add(uc);
_ucList.Add(uc);
}
Then this list can be iterated. Sure you could argue that "well .Controls is a collection too, so why add them to another list when they're already in an accessible collection" - for the reasons you're here; .Controls is a general purpose description of the hierarchy of all controls on a form, it contains stuff we don't want and is hard to iterate. This List is purely and simply all and only the stuff we're interested in
As an aside, the UI you have described is atypical. The more usual way of hiding and showing controls under the selection of something that holds a bit of text would be a TabControl. It might be easier to loop through too, if you will persist with this "search for UserControls in a collection of controls" method - tabcontrols have tabpages, tabpages would probably have a .Controls that just contains your UserControl. The tabpage intrinsically takes care of showing and hiding controls as pages are clicked on which could simplify your code
Thanks to everyone for the answers. As it happens, the issue was hiding in plain sight, right under my nose. In each of the User Controls, I had placed the Checkboxes and Combo Boxes inside a Group Box. It completely slipped my mind, so much so that I didn't even mention them in my question.
Thus, as #Caius had suggested in the comments, the code wasn't functioning because I had not addressed the Group Box Container holding these Controls. Once I removed the Group Boxes (used only for aesthetic purpose), the code started functioning properly.

How to automatic add the first line of text from a list box to a text box

Right I have got a list box which contains a list of tracks and when the track is pressed it moves to a second list box, what I now need to happen is have the first item that's in the second list box move automatic to a text box.
This is my current code for the first move
private void genreListBox_DoubleClick(object sender, EventArgs e)
{
playlistListBox.Items.Add(genreListBox.SelectedItem);
}
I am thinking it should be something like this
presentlyPlayingTextBox.AppendText(playlistListBox.);
But I'm not sure how to add the first line without clicking it.
I have tried this but I get an error for the value.
presentlyPlayingTextBox.Text = playlistListBox.SelectedItem.Value;
Normally you would use something like the 'SelectedIndexChanged' or 'SelectedValueChanged' action of a listbox, otherwise events like DoubleClick will fail if the keyboard is used to change the selection.
Also that event should be triggered on the second listbox when it is changed by the first.
EDIT:
On a standard Listbox, there is no .SelectedItem.Value, only .SelectedItem.
However as a listbox holds objects, not just text, you need to say you want the text value.
presentlyPlayingTextBox.Text = playlistListBox.SelectedItem.ToString();
I don't know if I fully understand your question, but if you're just attempting to move the first item from ListBox_2 to a textbox, would the following work?
presentlyPlayingTextBox.Text = playlistListBox.Items[0]?.Value; // C# >= 6
presentlyPLayingTextBox.Text = ((playlistListBox.Items == null) ? playlistListBox.Items[0].Value : "" ); // C# < 6
You could also create your own delegate/event that would fire when the user did some action.

Reference pairs of controls

I have a set of custom user controls, of type "ChartControl". I want to "pair" these (in some way), such that if having 10 controls, it's 5 pairs of 2 charts. The purpose of this is when I raise some specific event in one chart, I want the Form class to perform an action on both that chart, and it's pair chart, but not the other 8.
So what options do I have on how to "find" this 2nd chart of the pair? Or in other words: How to organize these charts in a type of list or class structure for this to be easy?
The challenge I see is that when receiving an event from a chart control, I can't simply loop through some list of controls to see where it belongs, as I can't compare the objects:
Operator '=' is not defined for types "UserControl" (VB.NET)
Would appreciate some ideas on how to do this. It's probably simple, but my brain seems a bit stuck here..
Create a new control which comprises of the two charts (and probably other controls as you deem appropriate). That way you can write methods for the control as well that will operate on both of them. It encapsulates the user control pairs to one central element.
You should be able to compare the objects using Object.Equals(). You can also group them in any container form and look at its Controls collection. This way you can make the separation GUI instead of program logic.
And: Is the error message you are getting because you are assigning (=) and not comparing (==)? :)
Some pseudocode:
private void ChartClicked(object sender, someargs...)
{
foreach (Control c in this.Controls)
{
if (Object.Equals(sender, c)
{
// This is the sender
}
}
}
or
private void ChartClicked(object sender, someargs...)
{
// Was it chart1 that was clicked? (We could use switch statement here to make the code cleaner)
if (Object.Equals(sender, chart1)
{
// Do something to chart5
chart5.Value = chart1.Value;
}
}

Bring Winforms control to front

Are there any other methods of bringing a control to the front other than control.BringToFront()?
I have series of labels on a user control and when I try to bring one of them to front it is not working. I have even looped through all the controls and sent them all the back except for the one I am interested in and it doesn't change a thing.
Here is the method where a label is added to the user control
private void AddUserLabel()
{
var field = new UserLabel();
userContainer.Controls.Add(field);
SendLabelsToBack(); // Send All labels to back
userContainer.Controls[field.FieldName].BringToFront();
}
Here is the method that sends all of them to the back.
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls);
label.SendToBack();
}
Yeah, there's another way. The Controls.SetChildIndex() also changes Z-order. The one with index 0 is the one on top. Doesn't buy you anything though, BringToFront() uses this method.
Your SendLabelsToBack() method as given cannot work, it will also send the label to added to the back. But your next statement fixes that again.
Okay, that doesn't work, which means the BringToFront() method doesn't get executed. Look in the Output window for a "first chance exception" notification. As written, your SendLabelsToBack() will cause an exception if the user control contains any control other than a UserLabel. Also, set a breakpoint after the BringToFront() call and check the value of userContainer.Controls[0].Name when it breaks.
Controls' z-index is per-container.
If you call BringToFront on a control that is inside a container (such as a Panel), it will not bring the container to the front.
Therefore, the control will only go in front of other controls in that container.
To see what containers your controls are in, you can use the Document Outline pane in the View menu.
EDIT: Your userContainer control is probably behind a different control.
Have you tried Invalidate() after BringToFront()? BringToFront does not raise the Paint event
try this:
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls)
{
label.SendToBack();
label.Invalidate();
}
}
I think you just need to change your last line:
userContainer.Controls[field.FieldName].BringToFront();
to this:
userContainer.Controls[field.Name].BringToFront();
When you use a string as the indexer for the Controls collection, it goes by the Name property of the control (not the FieldName property).
Since you're just trying to bring the most recently-added control to the top, this would also work:
userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();
From my experience looks like windows puts all controls belonging to one graphic container(pane, group box...etc) in a software collection. The collection is ordered by child index which is a property of every control in that container.
The trick is that children with the same index can and do exists. In this case windows will paint those children ordered relative to others but between them it will paint them in the reverse order they had been added to the container.
Long story short: for one container-you need to make sure controls have different indexes by changing ALL NOT just SOME of the indexes when you want to change the z-order. For example:
foreach (Control newControl in TopControl.Controls)
{
TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
}
where indexLogic(newControl ) is your method of calculation of the index of particular control.

Categories