How to get click event handler names of ToolStripDropDownItem? - c#

I have a old project in Windows Forms which has more than 300 menus with menu click events throughout the MDI form.
Is there any way to get the click event names in strings (e.g. "toolStripMenuItem_Click")?
I tried like this,
foreach (ToolStripMenuItem menu in menuStrip.Items)
{
foreach (ToolStripDropDownItem submenu in menu.DropDownItems)
{
var _events= submenu.GetType()
.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.OrderBy(pi => pi.Name).ToList();
}
}
But it always returns empty. What is correct way to achieve this?

Retrieving event handlers at runtime is not easy especially within the Forms framework where some events have special handling in the background.
A simpler approach (if you don't need the names at runtime but at design time) is to use regular expressions on your MyForm.designer.cs file to extract the names of the click handlers.
See this sample source:
private void button1_Click(object sender, EventArgs e)
{
string fileLocaton = #"C:\Users\nineb\source\repos\WindowsFormsApp37\WindowsFormsApp37\Form1.Designer.cs";
string fileContent = File.ReadAllText(fileLocaton);
// Find all menu items in the designer file
var matches = Regex.Matches(fileContent, #"System\.Windows\.Forms\.ToolStripMenuItem (.+?)\;");
foreach (Match match in matches)
{
string menuName = match.Groups[1].Value;
textBox1.AppendText("Menuitem " + menuName + Environment.NewLine);
// For each menu item, find all the event handlers
var clickMatches = Regex.Matches(fileContent,
#"this\." + Regex.Escape(menuName) + #"\.Click \+\= new System\.EventHandler\(this\.(.+?)\)\;");
foreach (Match clickMatch in clickMatches)
{
string handlerName = clickMatch.Groups[1].Value;
textBox1.AppendText("Eventhandler " + handlerName + Environment.NewLine);
}
}
}

Related

Dynamically Created Menu Item with attached code?

I'm reading 2 values from an INI File: The Section Name, & The value of the key named "Path"
[Game Name]
Path=C:\Game\Game.exe
What i'm trying to do is create a Context Menu Item with the caption being the Section "Game Name" and have it launch the application from the value of the "Path" key. I haven't worked much with dynamically created controls in the past, so i'm wondering if there's an easy way to create it, and assign a single line of code to it to launch the application.
Is it possible, or is there an easier way of going about it?
foreach (string SecHead in SectionHeader)
{
string[] Entry = myINI.GetEntryNames(SecHead);
if (Entry != null)
{
foreach (string EntName in Entry)
{
ArrayList row = new ArrayList();
row.Add(SecHead);
row.Add(myINI.GetEntryValue(SecHead, EntName));
DGV.Rows.Add(row.ToArray());
string filePath = Convert.ToString(myINI.GetEntryValue(SecHead, EntName));
//Create ContextMenu Entry from Data Above
Icon newIcon = Icon.ExtractAssociatedIcon(filePath);
}
}
}
I'll assume you know how to read the INI values and that they are in String variables. Let's also assume you are doing this in an event handler that supplies mouse coordinates, such as a MouseUp event:
var section = "section";
var gameExe = "c:\\somepath\\mygame.exe";
var menu = new ContextMenu();
var item = new MenuItem(section);
item.Click += (s, args) => { Process.Start(gameExe); };
menu.Items.Add(item);
menu.Show(this, new Point(e.X, e.Y));
Not tested live, but this should give you the general idea.

How to get value Drive from selecteditem on combobox and interact with listbox just for the selected item

I have been trying to figure this out so far 3 hours and could not get any way out, therefore i need help. Here is what I am trying:
I want to be able to select the Drive and hold the value of that, therefore, at the same time I want it to throw the details that I am trying to get such"free space , type, availability..etc"
InitializeComponent();
foreach (var Drives in Environment.GetLogicalDrives())
{
DriveInfo DriveInf = new DriveInfo(Drives);
if (DriveInf.IsReady == true)
{
comboBox1.Items.Add(DriveInf.Name);
// to get info for the selected drive
if (comboBox1.SelectedItem != null)
{
comboBox1.SelectedItem = listBox1.Items.Add("Drive Name: " + DriveInf.Name);
comboBox1.SelectedItem = listBox1.Items.Add("Total Size: " + DriveInf.TotalSize);
comboBox1.SelectedItem = listBox1.Items.Add("Available Space: " + DriveInf.AvailableFreeSpace);
comboBox1.SelectedItem = listBox1.Items.Add("Total Free Space: " + DriveInf.TotalFreeSpace);
}
}
}
So you want to be able to choose a drive from the combo box, and upon selection of drive from combo box populate a listbox with the drive info?
It sounds like you need to have an event handler for comboBox1.SelectionChanged event.
I don't have access to my IDE right now so the following isn't exactly copy and paste ready, but it'll give you an idea of what you need to do.
Here's what I would do: I would make a property for your form
private List<DriveInfo> driveInfoList = new List<DriveInfo>();
Then after your initialize component method I would put
foreach (var Drives in Environment.GetLogicalDrives()) {
DriveInfo DriveInf = new DriveInfo(Drives);
if (DriveInf.IsReady == true)
{
driveInfoList.Add(DriveInf);
comboBox1.Items.Add(DriveInf.Name);
}
}
Then I would put an event handler like such and make sure that your comboBox1's SelectionChanged event is hooked up to it:
private void comboBox1_SelectionChanged(object sender, EventArgs e) //or whatever form the event arguments take.
{
listBox1.Clear(); //or whatever clears the listbox of current items.
if (comboBox1.SelectedItem != null)
{
DriveInfo driveInfo = (from DriveInfo d in driveInfoList where d.Name == comboBox1.Text select d).First(); //or whatever you need to do to get the corresponding item from the list.
listBox1.Items.Add("Drive Name: " + d.Name);
listBox1.Items.Add("Total Size: " + DriveInf.TotalSize);
listBox1.Items.Add("Available Space: " + DriveInf.AvailableFreeSpace);
listBox1.Items.Add("Total Free Space: " + DriveInf.TotalFreeSpace);
}
Does that make sense?

Adding a wizard to a blank project: "The operation could not be completed. No such interface supported"

I've created a custom wizard that generates a windows form through code that lists out some SQL queries for the user. For almost all of the testing of the form and the wizard itself, adding it to a blank project would bring up the form and I could test the button click events and other general form stuff. Most recently I fleshed out the listbox's event listeners and ever since then I get this error:
Googling has lead me to a lot of posts about Ruby, which I'm not using. Other suggestions were reboot and re installation, and those proved unsuccessful. I attempted to comment out the listbox events but that did not keep the error from occuring, however, if it helps here are the events in question:
//-----------Event fired when a listbox object is double-clicked; populate the listbox with the new databases---------
public void dataList_MouseDoubleClick(object sender, EventArgs e)
{
//temp string used to hold the name of the clicked object
string selectedNAME = dataList.SelectedItem.ToString();
firstSEL.TableVar = selectedNAME;
foreach (tempDataVar t in dataVars)
{
if (t.TableVar == firstSEL.TableVar)
{
firstSEL = t;
}
}
string newQ = "SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + firstSEL.TableVar + "' AND TABLE_SCHEMA= '" + firstSEL.SchemaVar + "'";//order by TABLE_NAME'";
results = GetDataSet(bldr.ToString(), newQ);
//listBox1.Items.Clear();
foreach (DataRow row in results.Tables[0].Rows)
{
//foreach (object x in row.ItemArray)
//{
// listBox1.Items.Add(x.ToString());
//}
for (int x = 0; x < row.ItemArray.Length; x++)
{
if (x == 0)
{
colList.Items.Add(row.ItemArray[x]);
}
}
}
dataList.Enabled = false;
}
//-----------------------------Event that fires when the index of the second listbox changes--------------------------
private void colList_SelectedIndexChanged(object sender, EventArgs e)
{
btnYes.Enabled = true;
}
Noobie mistake fixed by a co-worker! I blindly copied and pasted the following code from a "How to make a wizard tutorial":
[ComVisible(true)]
[Guid("20184B81-7C38-4E02-A1E3-8D564EEC2D25"),
ProgId("MyNewWizard.Class1")]
This code needed to be directly above the MyNewWizard class and I accidentally pasted in my custom TempDataVar class in the white space between these lines and the start of the MyNewWizard class. If you're receiving a similar error then I'd suggest testing around the order of some of your attributes/classes!

Remove text from a richtext box if checkbox is checked on button click

Still new to C# and have been working on this program for sometime off and on added different features and what not. The program is for my job and it logs notes. Essentiall you type all the info into several different textboxes and then click a button and it combines the info into a large output richtextbox and adds some formatting to it and saves to a file and copies the info to the clipboard.
I'm wanting to set it up so that if i have a specific checkbox checked when i hit the button to process everything it will omit some of the formatting. I am using string builder to move the info into the output box.
Here is a sample of some of the code of how i have it working. Please let me know if anymore info is needed i will be happy to submit it.
private void save_button_Click(object sender, EventArgs e)
{
//Starts the Stringbuilder
System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
{
string cbrSame = custBtnText.Text;
if (cbrSameCbx.Checked)
{
custCbrText.Text = cbrSame;
}
//Writes textboxes to the stringbuilder
strBuilder.AppendLine("\u2022 CX NAME: " + custNameText.Text);
strBuilder.AppendLine("\u2022 BTN: " + custBtnText.Text);
strBuilder.AppendLine("\u2022 CBR: " + custCbrText.Text);
strBuilder.AppendLine("\u2022 MODEM: " + custModemText.Text);
//Statements to write checkboxes to stringbuilder
string checkBoxesLine = "\u2022 LIGHTS: ";
foreach (Control control in pnlCheckBoxes.Controls)
{
if (control is CheckBox)
{
CheckBox checkBox = (CheckBox)control;
if (checkBox.Checked && checkBox.Tag is string)
{
string checkBoxId = (string)checkBox.Tag;
checkBoxesLine += string.Format("{0}, ", checkBoxId);
checkBoxes = checkBoxesLine;
}
}
}
//Newline for checkboxes
strBuilder.AppendLine(checkBoxesLine);
strBuilder.AppendLine();
//Continues textboxes to stringbuilder
strBuilder.AppendLine("\u2022 TROUBLESHOOTING: " + tShootText.Text);
strBuilder.AppendLine();
strBuilder.AppendLine("\u2022 SERVICES OFFERED: " + svcsOfferedText.Text);
strBuilder.AppendLine();
strBuilder.AppendLine("\u2022 OTHER NOTES: " + otherNotesText.Text);
notesViewText.Text = strBuilder.ToString();
Clipboard.SetText(notesViewText.Text);
//....
Essentially i want to add a feature if checkbox1 is checked on that button press it omits the custModemText.text along with the \u2022 MODEM: and also the same for the \u2022 LIGHTS: and the string checkBoxesLine.
I have searched for something to do this but i am honestly at a loss about HOW to go about it which is limiting my ability to search for solutions. I have a sinking feeling i am going to have to redo the way i am processing my data but am unsure so any help would be appreciated.
Also this is a Win Form
What you need to do it you first check that the checkbox is checked or not. If it is checked then modify your text.
private void save_button_Click(object sender, EventArgs e)
{
// Add mandatory lines to a string.
if (checkBox1.Checked)
{
// Append optional lines to the string.
}
else
{
// Do something.
}
}
You don't need to do a foreach loop. Just check that checkbox on which you want to put condition.

Find and Find Next

I am using two forms, where one is a rich text editor with menus and a rich text box and the second form is for search and replace and contains four button and two text boxes. I have managed to do the find button but I am having problems with Find Next. I am using C# Windows Forms.
Here is the code I am using for Find:
private void button1_Click(object sender, EventArgs e)
{
RichTextBox frm1TB = ((Form1)this.Owner).txtDisplay;
int foundAt = frm1TB.Text.IndexOf(searchText.Text);
if (foundAt == -1)
{
MessageBox.Show("Not Found");
}
else
{
frm1TB.SelectionStart = foundAt;
frm1TB.SelectionLength = searchText.TextLength;
frm1TB.Focus();
}
}
Find next would be something like the following:
if (frm1TB.Text.Length >= frm1TB.Text.SelectionStart + frm1TB.Text.SelectionLength)
{
int foundAt = frm1TB.Text.IndexOf(
searchText.Text,
frm1TB.Text.SelectionStart + frm1TB.Text.SelectionLength);
}
You need to remember index at which you found your previous entry (or even better, at which you should start find next search) and then simply use IndexOf(string, int) overload, which allows you to start search at specified position. First, simply add next search start index field to your class:
private int nextSearchStartIndex;
Now, your Find method needs to keep update this index appropriately:
if (foundAt == -1)
{
this.nextSearchStartIndex = 0;
MessageBox.Show("Not Found");
}
else
{
this.nextSearchStartIndex = foundAt + searchText.TextLength;
// ...
}
And FindNext becomes trivial:
// ...
var foundAt = frm1TB.Text.IndexOf(searchText.Text,
this.nextSearchStartIndex);
// Here you can use exactly same update index logic as in Find
You can't use the IndexOf() method for it, you have to switch to Regular Expressions.
Here is an example how you can easily get all the search entries in RichtBox.Text:
using System.Text.RegularExpressions;
Regex re = new System.Text.RegularExpressions.Regex(searchText.Text.ToString(),RegexOptions.None);
MatchCollection mc = re.Matches(frm1TB.Text.ToString());
foreach (var ma in mc)
{
//do what you want
}

Categories