If I run the code in varying areas of my menu tree, I only get the one element, how would you firstly apply this logic to all sub components of this menu tree and secondly, illustrate the whole tree.
The code I have only shows 1 stage of each area applied
MessageBox.Show((ToolStripMenuItem).ToString());
So the above would only show File or Save or Open, rather than File Open or File Save.
Should I be using a foreach with my toolstripmenuitems?
Let's say I have MenuStrip with ToolStripMenuItem named fileToolStripMenuItem (with text File) which have subitems New and Open. Furthermore, Open has From file and Recent. To access all File's ToolStripMenuItems (it's children), you need recursive method, which goes through all levels (to access children, grandchildren...)
private IEnumerable<ToolStripMenuItem> GetChildToolStripItems(ToolStripMenuItem parent)
{
if (parent.HasDropDownItems)
{
foreach (ToolStripMenuItem child in parent.DropDownItems)
{
yield return child;
foreach (var nextLevel in GetChildToolStripItems(child))
{
yield return nextLevel;
}
}
}
}
This method takes first level menu item and returns IEnumerable<ToolStripMenuItem> sou you can then iterate through it (to get name, change some property etc).
Use it like this:
var list = GetChildToolStripItems(fileToolStripMenuItem);
In my example, that will return you the collection of subitems, like this: New, Open, From File, Recent.
You can easily go through collection and get item's text (to display in MessageBox, like this:
MessageBox.Show(string.Join(", ", list.Select(x=>x.Text).ToArray()))
or, if you prefer, like this:
foreach (ToolStripMenuItem menuItem in list)
{
MessageBox.Show(string.Format("item named: {0}, with text: {1}", menuItem.Name, menuItem.Text));
}
EDIT: after I saw comment that OP's idea is to get all items from MenuStrip, here's an example for that.
I wrote additional method that takes MenuStrip as parameter, iterates throught all ToolStripMenuItems and for each item calls GetChildToolStripItems method. Returns list of all top level items and all children and grand children...
private List<ToolStripMenuItem> GetAllMenuStripItems(MenuStrip menu)
{
List<ToolStripMenuItem> collection = new List<ToolStripMenuItem>();
foreach (ToolStripMenuItem item in menu.Items)
{
collection.Add(item);
collection.AddRange(GetChildToolStripItems(item));
}
return collection;
}
usage:
var allItems = GetAllMenuStripItems(menuStrip1)
Hope this helps.
In the end I used a logic around the following syntax, then building up the string at the end
ToolStripMenuItem ThisMenuItem = (ToolStripMenuItem)sender;
string WhatClicked = ThisMenuItem.ToString();
ToolStripMenuItem ThisMenuItemOwnerItem = (ToolStripMenuItem)(ThisMenuItem.GetCurrentParent() as ToolStripDropDown).OwnerItem;
Then you can obviously get deeper with
ToolStripMenuItem ThisOwnersOwnerItem = (ToolStripMenuItem)(ThisMenuItemOwnerItem.GetCurrentParent() as ToolStripDropDown).OwnerItem;
and so forth adding checks to avoid null exceptions.
Related
I have a question regarding use of "Tag" :
I have a ListBox, or ListView, in which I have the name of my objects, I addes a "Tag" property to find its corresponding object :
foreach(Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
ListViewItem item = new ListViewItem(op_ass.Nom);
item.Tag = op_ass;
listBoxAss1.Items.Add(op_ass.Nom);
}
Now what I would like, is when I select an item in my list(or several), make an action on corresponding objects. But how can I find them back?
For example I want to remove selected objects from a List, or get the list of Operation ID (without displaying ID in my list).
Looks like you are adding the property, op_ass.Nom into the listbox instead of the ListViewItem, item. Modify your code as follows:
foreach (Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
ListViewItem item = new ListViewItem(op_ass.Nom);
item.Tag = op_ass;
// Add the list view item instead of op_ass.Nom
listBoxAss1.Items.Add(item);
}
Now you should be able to retrieve the tag from selected item/items as follows:
var operation = ((listBox1.SelectedItem as ListViewItem).Tag) as Operation;
Alternatively, you could think of using data binding as follows:
foreach (Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
}
listBoxAss1.DataSource = ListOpAss1;
listBoxAss1.DisplayMember = "Nom";
And access the data bound object as follows:
var operation = listBox1.SelectedItem as Operation;
using foreach is kind of deprecated you can look into implemented functions in list of objects
ListOpAss1.ForEach(x=>
{
x.getNom(Properties.Settings.Default.Langue);
var item = new ListViewItem(x.Nom);
item.Tag = x;
listBoxAss1.Items.Add(x.Nom);
});
in order to select an item in a list you can use SingleOrDefalt() or Skip(count) take (count) for multiple files or you can run native querys with conditions to search the list like this
var items = collection.Where(x=> x.City == "Burgas").ToList(); //You can use select if you want only certain properties of the object to be selected
///then you can use that new item list to remove the objects from the collection list like this
items.ForEach(x=>
{
collection.Remove(x);
});
In this method i'm doing a search in TreeNodes:
private void FindByText()
{
TreeNodeCollection nodes = treeView1.Nodes;
foreach (TreeNode n in nodes)
{
FindRecursive(n);
}
}
And the FindRecursive:
private void FindRecursive(TreeNode treeNode)
{
foreach (TreeNode tn in treeNode.Nodes)
{
string result = Regex.Replace(tn.Text, #"^\d*\.\s*", string.Empty);
if (tn.Text.Contains(this.txtNodeTextSearch.Text))
{
tn.BackColor = Color.Yellow;
tn.EnsureVisible();
count++;
label11.Text = count.ToString();
}
FindRecursive(tn);
}
}
In the FindRecursive method i did:
tn.EnsureVisible();
But if for example i searched and it found 20 items it will scroll down and show me the last found item.
Then i will need to scorll up to see the other items it found.
I need that it will make like tn.EnsureVisible(); but will point on the top first item and if i will like i will scroll down to see the others.
I hope I get your point.
You will need to "sort" your code the other way around, such that the "top" item ist the last one marked and focussed on with EnsureVisible().
So first put the recursion call right before your compare->EnsureVisible. This will cause the child items marked before the current top node gets checked and (possibly) marked visbile and focussed on.
Then, if required, reverse the TreeNode Collection you loop through - it might be possible like this Why does IList<>.Reverse() not work like List<>().Reverse.
So them the First Top Item will be checked last.
Hi there I have searched for a while now and can't seem to find a solution to my problem, I have tried multiple methods to select multiple items in my listbox through code however none have worked, The best result I got was 1 selected item in my listbox.
Basically I want to select multiple items of the same value.
below is my code, sorry if I seem newbie but I am new to programming and still learning basic stuff.
foreach (string p in listBox1.Items)
{
if (p == searchstring)
{
index = listBox1.Items.IndexOf(p);
listBox1.SetSelected(index,true);
}
}
So as you can see I am trying to tell the program to loop through all the items in my listbox, and for every item that equals "searchstring" get the index and set it as selected.
However all this code does is select the first item in the list that equals "searchstring" makes it selected and stops, it doesn't iterate through all the "searchstring" items.
As suggested in the comment, you should set SelectionMode to either MulitSimple or MultiExpanded depending on your needs, but you also need to use for or while loop instead offoreach, because foreach loop doesn't allow the collection to be changed during iterations. Therefore, even setting this Property won't make your code run and you will get the exception. Try this:
for(int i = 0; i<listBox1.Items.Count;i++)
{
string p = listBox1.Items[i].ToString();
if (p == searchstring)
{
listBox1.SetSelected(i, true);
}
}
You can set SelectionMode either in the Properties window when using designer or in, for instance, constructor of your Form using this code:
listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple;
For my current project i made a MDIform with "menuStrip" and a couple of "ToolStripMenuItem".
a couple of buttons and a devexpress "NavbarControl"
The intention is that the user logs in with a userID
the application will get a datarow for a specific "Control"
in this row theirs a bool, if its true the Item must be visible, otherwise the item must be invisible.
the Datarow also contains the name of the item.
so i uses:
this.Controls[item].Visible = true;
item = string(name of item)
if i use this to hide the menustrip itself, it works
if i try it on the MenuStipItems, it gives a null reference exception.
how can i control the items INSIDE the MenuStip, only by name of the item???
Code:
DataTable dt = GetData();
foreach (DataRow row in dt.Rows)
{
string item = row["ItemNaam"].ToString();
foreach (string rol in Rollen)
{
DataRow dr = GetDataByItemNaam(item);
if (Convert.ToBoolean(dr[rol]) == true)
{
this.Controls[item].Visible = true; //Show Item
}
}
}
The MenuStrip control has it's own collection. So to reference the menu strip items, reference the items from the menustrip parent:
if (this.menuStrip1.Items.ContainsKey(item))
this.menuStrip1.Items[item].Visible = true;
I've solved the problem:
I created a foreach loop within a foreach loop where
each loop looks for the name of the item, and then for the name of the item in the previous item.
If the name matches the given name, it sets the visibility to true.
This is for 2 levels, I created an additional two extra foreach loops to go even deeper (inception) to 4 levels of items in the menu.
Perhaps its not the right/fastest way, but it works like it should.
I have three sets of listboxes, I move items from lb1 to lb2, from lb3 to lb4 and from lb5 to lb6. The listboxes on the left contains the same items and I don't want the user to be able to submit the page if one or more items from the left listboxes is added to more than one listbox to the right. For example, item A in lb1, lb3 and lb5 can only be saved in either lb2, lb4 or lb6, not in two or three of them.
I want to perform this check before submitting the page (and later on I will add validation with javascript) and I wonder what is the most efficient way to do this.
Add all items to a list and check if there are any duplicates?
Thanks in advance.
Edit:
something like this:
List<string> groupList = new List<string>();
foreach (ListItem item in lbFullAccess.Items)
{
groupList.Add(item.Value.ToString());
}
foreach (ListItem item in lbContributor.Items)
{
groupList.Add(item.Value.ToString());
}
foreach (ListItem item in lblReadOnly.Items)
{
groupList.Add(item.Value.ToString());
}
Well, there's a hundred different ways you could do it. Absolutely nothing wrong with your suggestion of iteration.
You could have a little fun with LINQ:
public bool AreAllValuesUnique()
{
// Build up a linq expression of all of the ListItems
// by concatenating each sequence
var allItems = lbFullAccess.Items.Cast<ListItem>()
.Concat(lbContributor.Items.Cast<ListItem>())
.Concat(lbReadOnly.Items.Cast<ListItem>());
// Group the previous linq expression by value (so they will be in groups of "A", "B", etc)
var groupedByValue = allItems.GroupBy(i => i.Value);
// Finally, return that all groups must have a count of only one element
// So each value can only appear once
return groupedByValue.All(g => g.Count() == 1);
}
Not really sure about the performance of calling Cast (converting each element of the ListItemCollection to a ListItem, resulting in an IEnumerable) on each collection, but it is probably negligible.