Find multiple controls with by partially matching their name - c#

I currently have 100+ labels, with names like:
labelNumber1
labelNumber2
labelNumber3
labelNumber4
....
labelLetter1
labelLetter2
labelLetter3
labelLetter4
....
How would I find all the labels that have "Number" in the controls name?
Instead of having to type out labelNumber1.text = "hello", etc.
I have tried regex and foreach with wild cards but did not succeed.
I have looked on msdn.microsoft.com about using regex with a control.

You can loop through the Controls collection of the form and just check the name of each control that it contains something like 'Label'. or you could check that the control is a typeof TextBox, Label, etc.
E.g.
foreach (Control control in form.Controls)
{
if (control.Name.ToUpper().Contains("[Your control search string here]"))
{
// Do something here.
}
if (control is TextBox) {
// Do something here.
}
}

you can filter the list of controls to only return the labels. You would also want to make sure the name is greater than 11 chars.
List<Label> allNumberLabels = new List<Label>();
foreach (Label t in this.Controls.OfType<Label>())
{
if (t.Name.Length > 11)
{
if (t.Name.Substring(5, 6).Equals("Number"))
{
allNumberLabels.Add(t);
}
}
}

I know this is an old question, but I am here now, and:
The question asks about searching for multiple controls. This solution actually applies to any type of control.
OP was conflicted between using "Contains" or regex. I vote for regex! string.Contains is a bad idea for this kind of filter, since "CoolButton" has a "Button" in it too"
Anyway, here is the code:
public List<TControlType> FindByPattern<TControlType>(string regexPattern)
where TControlType:Control
{
return Controls.OfType<TControlType>()
.Where(control => Regex.IsMatch(control.Name, regexPattern))
.ToList();
}
Usage:
//some regex samples you can test out
var startsWithLabel = $"^Label"; //Matches like .StartsWith()
var containsLabel = "Label"; //Matches like .Contains()
var startsWithLabelEndsWithNumber = "^Label.*\\d+&"; //matches Label8sdf12 and Label8
var containsLabelEndsWithNumber = "Label.*\\d+&"; //matches MyLabelRocks83475, MyLabel8Rocks54389, MyLabel8, Label8
var hasAnyNumber= "^CoolLabel\\d+$"; //matches CoolLabel437627
var labels = FindByPattern<Label>("^MyCoolLabel.*\\d+&");
var buttons = FindByPattern<Button("^AveragelyCoolButton.*\\d+&");

Related

How to access a group of Text Boxes based on the Index Id in their Name

I have 16 text boxes in my Form whose names are suffixed sequentially from 1 to 16 respectively.
i.e. The 16 test boxes are names TextBox1, 'TextBox2, .... all the way until the 16th one, which is namedTextBox16`.
I would like to read the contents of these 16 text boxes in a loop and modify the ith TextBox's contents or properties based on a certain condition.
How do I do this?
If you use WinForms, easiest way is to store text boxes references in array, in constructor of window:
TextBox[] data = new TextBox[16]{textBox1,textBox2, [...],textBox16};
then you can use for loop to access them.
You can try something like this:
Dictionary<string, string> yourValues = new Dictionary<string, string>();
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
yourValues.Add(((TextBox)x).Name, ((TextBox)x).Text);
}
}
NOTE: On your future question please provide more information and make your question more clear.
i would try to find and modify using Linq:
using System.Linq;
//...
int x = 5; //number of textbox to search
var textbox = this.Controls.OfType<TextBox>().Single(tb => tb.Name.EndsWith(x.ToString()));
textbox.Text = "abc";
In case you have to loop thru all the texboxes in form, you can do something like this:
List<TextBox> textboxes = this.Controls.OfType<TextBox>().ToList();
foreach (TextBox box in textboxes)
{
box.Text = "something";
}
Easiest way according to what you specified is to use Linq.
Let's assume you have 3 TextBoxes :
// 1st -> which is named meTextBox1
// 2nd -> which is named meTextBox2
// 3rd -> which is named meTextBox3
As you can see from above every line differs only by the number ( index .. call it whatever you want ).
Now you can make your base "query" which would look like :
const string TB_NAME = "meTextBox{0}";
And as you can presume right now this will be used inside of string.Format method. Now to retrieve desired TextBox all you have to do is to make Linq statement :
string boxName = string.Format(TB_NAME, 7); // retrieve 7th text box
TextBox tBox = Controls.OfType<TextBox>().FirstOrDefault(tb => tb.Name == boxName);
This example does not consider nested Controls but you can make do this recursively which will retrieve nested Controls:
TextBox ByIndex(int idx, Control parent)
{
TextBox result = null;
string searchFor = string.Format(TB_NAME, idx);
foreach(Control ctrl in parent.Controls)
{
if(!(ctrl is TextBox) && ctrl.HasChildren)
{
result = ByIndex(idx, ctrl);
if( result != null)
break;
}
else if(ctrl is TextBox)
{
if(ctrl.Name = searchFor)
{
result = ctrl as TextBox;
break;
}
}
}
return result;
}
To use above method you can just call it like such :
public class MeForm : Form
{
//.. your code here ..
void meImaginaryMethodToRetrieveTextBox()
{
int meRandomIndex = 7;
TextBox tb = ByIndex(meRandomIndex, this);
// rest of the code...
}
}

If string in list occurs in string, then add to list

had a look around and found many similar questions but none matching mine exactly.
public bool checkInvalid()
{
invalidMessage = filterWords.Any(s => appmessage.Contains(s));
return invalidMessage;
}
If a string is found that matches a string in the list the boolean invalidMessage is set to true.
After this though I would like to be able to add each string found to a list. is there a way I can do this using .Contains() or can someone recommend me another way to go about this?
Many thanks.
Well, from your description, I thought here is what you want:
// Set of filtered words
string[] filterWords = {"AAA", "BBB", "EEE"};
// The app message
string appMessage = "AAA CCC BBB DDD";
// The list contains filtered words from the app message
List<string> result = new List<string>();
// Normally, here is what you do
// 1. With each word in the filtered words set
foreach (string word in filterWords)
{
// Check if it exists in the app message
if (appMessage.Contains(word))
{
// If it does, add to the list
result.Add(word);
}
}
But as you said, you want to use LINQ, so instead of doing a loop, you can do it like this:
// If you want to use LINQ, here is the way
result.AddRange(filterWords.Where(word => appMessage.Contains(word)));
If what you want is to gets the words in filterWords that are contained in appmessage you can use Where:
var words = filterWords.Where(s => appmessage.Contains(s)).ToList();

Get all <td> title of a table column with coded ui

I need to check a filter function on a table.
This filter is only on the first cell of each row and I'm trying to figure out how to get all those values...
I tried with something like
public bool CheckSearchResults(HtmlControl GridTable, string FilterTxt)
{
List<string> Elements = new List<string>();
foreach (HtmlCell cell in GridTable.GetChildren())
{
Elements.Add(cell.FilterProperties["title"]);
}
List<string> Results = Elements.FindAll(l => l.Contains(FilterTxt));
return Results.Count == Elements.Count;
}
but I get stuck at the foreach loop...
maybe there's a simply way with linq, but i don't know it so much
edit:
all the cells i need have the same custom html tag.
with this code i should get them all, but i don't know how to iterate
HtmlDocument Document = this.UIPageWindow.UIPageDocument;
HtmlControl GridTable = this.UIPageWindow.UIPageDocument.UIPageGridTable;
HtmlCell Cells = new HtmlCell(GridTable);
Cells.FilterProperties["custom_control"] = "firstCellOfRow";
also because there's no GetEnumerator function or query models for HtmlCell objects, which are part of Microsoft.VisualStudio.TestTools.UITesting.HtmlControl library -.-
edit2:
i found this article and i tried this
public bool CheckSearchResults(string FilterTxt)
{
HtmlDocument Document = this.UIPageWindow.UIPageDocument;
HtmlControl GridTable = this.UIPageWindow.UIPageDocument.UIPageGridTable;
HtmlRow rows = new HtmlRow(GridTable);
rows.SearchProperties[HtmlRow.PropertyNames.Class] = "ui-widget-content jqgrow ui-row-ltr";
HtmlControl cells = new HtmlControl(rows);
cells.SearchProperties["custom_control"] = "firstCellOfRow";
UITestControlCollection collection = cells.FindMatchingControls();
List<string> Elements = new List<string>();
foreach (UITestControl elem in collection)
{
HtmlCell cell = (HtmlCell)elem;
Elements.Add(cell.GetProperty("Title").ToString());
}
List<string> Results = Elements.FindAll(l => l.Contains(FilterTxt));
return Results.Count == Elements.Count;
}
but i get an empty collection...
Try Cell.Title or Cell.GetProperty("Title"). SearchProperties and FilterProperties are only there for searching for a UI element. They either come from the UIMap or from code if you fill them out with hand. Otherwise your code should should work.
Or you can use a LINQ query (?) like:
var FilteredElements =
from Cell in UIMap...GridTable.GetChildren()
where Cell.GetProperty("Title").ToString().Contains(FilterTxt)
select Cell;
You could also try to record a cell, add it to the UIMap, set its search or filter properties to match your filtering, then call UIMap...Cell.FindMatchingControls() and it should return all matching cells.
The problem now is that you are limiting your search for one row of the table. HtmlControl cells = new HtmlControl(rows); here the constructor parameter sets a search limit container and not the direct parent of the control. It should be the GridTable if you want to search all cells in the table. Best solution would be to use the recorder to get a cell control then modify its search and filter properties in the UIMap to match all cells you are looking for. Tho in my opinion you should stick with a hand coded filtering. Something like:
foreach(var row in GridTable.GetChildren())
{
foreach(var cell in row.GetChildren())
{
//filter cell here
}
}
Check with AccExplorer or the recorder if the hierarchy is right. You should also use debug to be sure if the loops are getting the right controls and see the properties of the cells so you will know if the filter function is right.
I resolved scraping pages html by myself
static public List<string> GetTdTitles(string htmlCode, string TdSearchPattern)
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlCode);
HtmlNodeCollection collection = doc.DocumentNode.SelectNodes("//td[#" + TdSearchPattern + "]");
List<string> Results = new List<string>();
foreach (HtmlNode node in collection)
{
Results.Add(node.InnerText);
}
return Results;
}
I'm freakin' hating those stupid coded ui test -.-
btw, thanks for the help

Selected Checkbox from a bunch of checkboxes in .c#.net

The problem is faced under c# .NET, Visual Studio, Windows Form Application
I have a bunch of checkboxes placed randomly in one form and in one panel.
So, If any checkbox is selected in the form its value is supposed to be added up.
Bottomline: Instead of using plenty of "If-else loops", to evaluate whether its been checked or not. I wanna simplify it using a "for loop ".
Is there any Checkbox group name type feature, which I can use???
I wanna code something like this:
for(int i=0;i<checkboxes.length;i++)
{
string str;
if(chkbox.checked)
{
str+=chkbox.value;
}
}
Where checkboxes is a group name.
You can use a simple LINQ query
var checked_boxes = yourControl.Controls.OfType<CheckBox>().Where(c => c.Checked);
where yourControl is the control containing your checkboxes.
checked_boxes is now an object which implements IEnumerable<CheckBox> that represents the query. Usually you want to iterate over this query with an foreach loop:
foreach(CheckBox cbx in checked_boxes)
{
}
You also can convert this query to a list (List<Checkbox>) by calling .ToList(), either on checked_boxes or directly after the Where(...).
Since you want to concatenate the Text of the checkboxes to a single string, you could use String.Join.
var checked_texts = yourControl.Controls.OfType<CheckBox>()
.Where(c => c.Checked)
.OrderBy(c => c.Text)
.Select(c => c.Text);
var allCheckedAsString = String.Join("", checked_texts);
I also added an OrderBy clause to ensure the checkboxes are sorted by their Text.
CheckBox[] box = new CheckBox[4];
box[0] = checkBox1;
box[1] = checkBox2;
box[2] = checkBox3;
box[3] = checkBox4;
for(int i=0; i<box.length; i++)
{
string str;
if(box[i].checked== true)
{
str += i.value;
}
}
I think this code will work with DotNet4.0. Plz let me know any error occurs. Treat 'box' as regular array.
If all the checkboxes are in a groupbox you can do this:
foreach(Control c in myGroupBox.Controls)
{
if (c is CheckBox)
{
//do something
CheckBox temp = (CheckBox)c;
if(temp.Checked)
//its checked
}
}
Subscribe all checkboxes to one CheckedChanged event handler and build your string when any checkbox checked or unchecked. Following query will build string, containing names of all Form's checked checkboxes:
private void Checkbox_CheckedChanged(object sender, EventArgs e)
{
// this will use all checkboxes on Form
string str = Controls.OfType<CheckBox>()
.Where(ch => ch.Checked)
.Aggregate(new StringBuilder(),
(sb, ch) => sb.Append(ch.Name),
sb => sb.ToString());
// use string
}
I suppose other than subscribing to event CheckedChanged there is no alternative even if it is contained in some panel or form, You have to use if else,
if it would have been web base eg asp.net or php we could use jquery because it gives us the option to loop through each particular event using .each and getting its value

Converting string to ToolStripMenuItem

I have a menu structure already set up on a form and I want to programatically enable or disable certain menu items using a database.
I have got to the last stage where I have a class of AllowedMenu and CodeNames (which match the toolstripmenuitems exactly), and all I want to do it convert the CodeName into a ToolStripMenuItem from a String.
How could I do this?
Seem to have found something that works...
var m = menuStrip1.Items.Find(menuItem.CodeName, true);
var o = m.ToList();
foreach (var p in o)
{
p.Visible = false;
}
Thanks all..
You can access ToolStripItems throught Items property of the ToolStrip. If you have exactly name of the item (in CodeName variable), you could do something like this:
if (toolStrip1.Items.ContainsKey(CodeName)) //Just in case...
{
var yourItem = toolStrip1.Items[CodeName];
}

Categories