I have a list of string with which I want to create a menu of ToolStripItem (neither the list size nor its content is know at debug) and I want each item to execute the same event, so I go through the list with that code:
foreach (string i in items)
{
ToolStripItem item = (ToolStripItem)toolStripMenuItem1.DropDownItems.Add(i);
item.Click += new EventHandler(item_Click);
}
the problem is that in the item_Click method I need to know which of the above items triggered the event. If I were in WPF, I would have used RoutedEventArgs and its .Source proprety but since I am only in a regular Windows Forms app, I'm not quite sure how to do it. Is there a simple way to do it?
Thank you.
Use sender parameter in your click event
var item = sender as ToolStripItem;
if(item != null)
{
...
}
Related
I'm looping a collection of strings, coming from a database; for each entry, I create a new Button which is then added to a FlowLayoutPanel.
The Text of each Button is set to the current item in the string collection.
I'd like to assign an EventHandler to the Click event of each Button, however I am only able to access the Properties of a Button.
I have to cast the last entry of the FlowLayoutPanel's Controls collection to Button and add the Event Handler to this instance.
Does anyone know the reason why I can't access anything else then Properties? Is there a cleaner way of coding that?
List<string> temp = Database.GetNames();
foreach(string s in temp)
{
flp_main.Controls.Add(new Button()
{
Text = s.name
});
Button b = (Button)flp_main.Controls[flp_main.Controls.Count - 1];
b.Click += B_Click;
}
Asking for Improvements on Code Quality
I'm attempting to create a dynamic menu strip in my program. Here's an example of what it looks like right now:
Creating the ToolstripMenuItems dynamically itself is easy. What I plan to do is to check if the current month already exists in the folder paths that my program works with, and if it doesn't then it will create an extra menu strip with the date (for example once we hit August, it should create August 2014, with sub-items "NL" & "PL").
However the part that i am stuck at is how to link functionality to these dynamically created sub-items. As I've been unable to find a way to do this, both the "NL" and "PL" tabs open a specific .TXT file of that specific month (which is created elsewhere in the program). However when I make them dynamically, I can't find a way to make them do this and they just don't have any functionality.
At this point I find myself manually creating new menu items & code every month for this. And I would very much prefer the program to run itself.
Any tips on how to make dynamic menuitems functional?
Added code:
private void CreateMenu()
{
ToolStripMenuItem item = new ToolStripMenuItem();
item.Text = "Logs";
DirectoryInfo dir = new DirectoryInfo(#"Y:\Heineken\Tools\Logs\");
foreach (DirectoryInfo directory in dir.GetDirectories())
{
ToolStripMenuItem dateItem = new ToolStripMenuItem(directory.Name);
ToolStripMenuItem NLMenu = new ToolStripMenuItem("NL"); // <--- This needs to open a specific text file on a network share
ToolStripMenuItem PLMenu = new ToolStripMenuItem("PL"); // <--- This needs to open a specific text file on a network share
dateItem.DropDownItems.Add(NLMenu);
dateItem.DropDownItems.Add(PLMenu);
item.DropDownItems.Add(dateItem);
}
menuToolStripMenuItem.DropDownItems.Add(item);
}
It would help if you would post some code snippet of how you are dynamically creating your menu items. In general, you can link functionality to dynamic menu entries by simply passing a delegate into the ToolStripMenuItem constructor, like so:
var entry = new ToolStripMenuItem("NL", null, delegate
{
//TODO: do something
});
owner.DropDownItems.Add(entry);
This assumes the variable "owner" is your parent menu entry.
Edit: Given the code you supplied, you could do it like this
private void OpenTextFile(string id)
{
//TODO: logic for opening the shared file
}
private void CreateMenu()
{
ToolStripMenuItem item = new ToolStripMenuItem();
item.Text = "Logs";
DirectoryInfo dir = new DirectoryInfo(#"Y:\Heineken\Tools\Logs\");
foreach (DirectoryInfo directory in dir.GetDirectories())
{
ToolStripMenuItem dateItem = new ToolStripMenuItem(directory.Name);
ToolStripMenuItem NLMenu = new ToolStripMenuItem("NL", null, (sender, e) => OpenTextFile("NL"));
ToolStripMenuItem PLMenu = new ToolStripMenuItem("PL", null, (sender, e) => OpenTextFile("PL"));
dateItem.DropDownItems.Add(NLMenu);
dateItem.DropDownItems.Add(PLMenu);
item.DropDownItems.Add(dateItem);
}
menuToolStripMenuItem.DropDownItems.Add(item);
}
You need to hook up the click event handler to the dynamically created ToolstripMenuItems. In the click event handler you can then cast the sender to ToolstripMenuItem and access any properties you may need to work out which text file you need to load.
For example this click handler will give a message box with the text of the menu item:
private void toolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show(((ToolStripMenuItem)sender).Text);
}
To add a new dynamic menu item and link it to the click handler you can do this:
ToolStripMenuItem newItem = new ToolStripMenuItem("Dynamic Option");
newItem.Click += toolStripMenuItem_Click;
existingToolStripMenuItem.DropDownItems.Add(newItem);
Edit after code posted
You can store the file that is supposed to be opened when the menu item is clicked in the Tag property. When the menu item is then clicked you can open the file based on the path in the Tag.
For example, in your CreateMenu method you would need to do something like this:
ToolStripMenuItem NLMenu = new ToolStripMenuItem("NL");
//store the filename here for later
NLMenu.Tag = Path.Combine(dir.FullName, "nl.txt");
//attach the click handler
NLMenu.Click += toolStripMenuItem_Click;
//repeat for PLMenu...
Then in the click handler you can do this:
private void toolStripMenuItem_Click(object sender, EventArgs e)
{
string filename = ((ToolStripMenuItem)sender).Tag;
//do something with the file.
}
I have a tab control through which the user can right-click within one of several richTextBoxes. The textBoxes use the same contextMenuStrip control, and I need to determine which textBox is the active one within the contextMenuStripCopyPaste_Opening event. I would think that the code to determine this would be
tabControl1.SelectedTab.ActiveControl.Name but the ActiveControl property is not available. this.ActiveControl.Name just gives me the name of the tabControl.
How can I determine which textBox is the active control within the tabControl?
You can use the sender paramter to get the ContextMenuStrip then call the ContextMenuStrip.SourceControl property to get the control that opened the context menu.
In this case you can try the following code.
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
var ctxStrip = sender as ContextMenuStrip;
if (ctxStrip == null)
return;
var rtb = ctxStrip.SourceControl as RichTextBox;
if (rtb == null)
return;
}
This code simply casts the sender object to a ContextMenuStrip if this is null then return. (Although should never be). The next line captures the SourceControl and casts the control to a RichTextBox.
If the source control is not a RichTextBox then the result will be null and we cancel as this shouldn't be null unless you bind the context menu to other controls aswell.
I'm not finding anything that is there by default. I would create a list of the rich text boxes, and then use a LINQ statement as the LINQ Select statement would return only the rich text box that has the focus. Something like this.
List rtbList = new List {RichTextBox1, RichTextBox2, RichTextBox3, RichTextBox4}
var FocusedRTB = rtbList.Select(x => x.Focused == true);
switch (FocusedRTB.Name)
{Execute Code for each RichTextBox
}
I've a common ContextMenuStrip for every workspace control of my application.
This ContextMenuStrip contains 4 Items ("Move front", "Move back", and "Delete control").
Now I want to extend it for one control.
There's a DataGridView on this control and I want an additional item to delete the selected DataGridViewRow.
This is the code I tried:
private void extendContextMenuOfDataGridViewRow (DataGridViewRow row) {
ContextMenuStrip ctx = new ContextMenuStrip();
foreach (ToolStripMenuItem item in this.ContextMenuStrip.Items) {
ctx.Items.Add(item);
}
ctx.Items.Add(new ToolStripSeparator());
ToolStripMenuItem ctxDeleteRow = new ToolStripMenuItem("Delete row");
ctxDeleteRow.Name = "ctxDeleteRow";
ctxDeleteRow.Click += new EventHandler(ctxDeleteRow_Click);
ctx.Items.Add(ctxDeleteRow);
row.ContextMenuStrip = ctx;
}
After the first item of the foreach loop was added to ctx.Items the debugger leaves the whole method and the first item is missing at the common ContextMenuStrip.
How do I do that right?
If you want to extend functionally of some control, you can either
a) create an extension method
public void DoSomething(this MyExtendedControl mec, DataGridViewRow row)
{
}
b) create a new class inheriting from your unsatisfactory control (or even create a completely new control), when you can override/add things as needed
Depends on your specific needs, couldn't understand from your description...
I haven't worked with WinForms for ages, but are you sure that you can keep the same Row object assigned to two different Strips at once?
foreach (ToolStripMenuItem item in this.ContextMenuStrip.Items) {
ctx.Items.Add(item);
}
I seriously doubt this should work by design because a row has to “talk” to its parent, and by adding it to another strip I'm afraid you're re-assigning the parent.
Instead, I would have added an item to the common menu but with its Visible property to false.
Then I would catch the menu opening event and make item visible if target is a DataGridViewRow.
I am trying to get a Listbox Item by below code. Basically what i am trying to do is create a tempdatelist and then set the itemsource of Listbox to tempdatelist.
if (App.Saveholidayplan[App.selectedlistindex].travel.Count > 0)
foreach (var dictobj in App.Saveholidayplan[App.selectedlistindex].travel[0].DummyRepository)
tempdatelist.Add(dictobj.Key);
lst_mainlist.ItemsSource = tempdatelist;
ListBoxItem item = this.lst_mainlist.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
//* item is alway null, that is the problem
if(item != null)
But in the above code item retuns null.
When i check Online some suggested to call ItemContainerGenerator.StatusChanged event.
But i am not able to find this event in WP7?
Is there a StatusChanged event in WP7 and if not what is the alternative?
I had this problem too. The solution is to wait for the UI to render by using the dispatcher, like this:
this.Dispatcher.BeginInvoke(() =>
{
ListBoxItem item = this.lst_mainlist.ItemContainerGenerator.ContainerFromIndex(i);
//...
});