How to extend an existing ContextMenuStrip? - c#

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.

Related

C# - Menustrip- Check if Parent exists and get the reference to them

First of all Thanks for your Time! I hope you can help me =/
I have a MenuStrip where i want to add items dynamically.
What i want to do :
If a Partent with exactly the same name already exists the Childs should be add to this parent instead creating a new Parent(MenuStripItem) with the same name.
My Code does currently checks if the parent already exists (which works fine) but the problem is i cant get the reference to this parent -> firstItem=var doesnt work -> cant convert ToolStripItem to ToolStripMenuItem... and changing the "firstItem" to ToolStripItem gives me an Error because i cant use "firstItem.DropDownItems.Add(withChild);" anymore to add a Child later on...
private void AddNewMenuStrips(string [,] NewMenuStripInfo)
{
ToolStripMenuItem firstItem;
bool alreadyexists = false;
string someItem = "Settings"; // the parent im looking for
var items = menuStrip2.Items.Find(someItem+"ToolStripMenuItem",false); //here it checks if parent already exists. Which Works but i cant get the reference of the parent to "firstItem"
foreach (var item in items)
{
MessageBox.Show("FOUND"+item.Name);
firstItem = var; // ERROR cant convert ToolStripItem to ToolStripMenuItem
alreadyexists=true;
}
if (alreadyexists == false) { firstItem = new ToolStripMenuItem(someItem); }
}
THANKS in advance!
ToolStripMenuItem is a class which represents top level menu items and derives (not directly) from ToolStripItem.
Therefore to retrieve the parent menu item you can use a cast:
foreach (var item in parents)
{
MessageBox.Show("FOUND" + item.Name);
firstItem = item as ToolStripMenuItem;
alreadyexists = true;
// break;
}

ListView.Items.Add adding a ListViewItem to wrong ListView

I have two ListView objects in my code, MovieList and UserFriendList. I have a method that looks like this
public void passFriends(ListViewItem[] friends)
{
foreach (ListViewItem tempItem in friends)
{
ListViewItem temp = new ListViewItem();
temp = (ListViewItem)tempItem.Clone();
UserFriendList.Items.Add(temp);
}
}
The method is designed to pass an array of ListViewItems from one form to another, and then add each listview item to the UserFriendList. However, when I actually perform the action, the ListViewItem (a User) is added to my MovieList instead of my UserFriendsList
Does anybody know why this could be happening?
This question can be closed. I found the issue with my problem. A section of legacy code that was used to demonstrate list switching wasn't removed and it was changing the listview of UserFriendList

C# - Add all Input Controls to List<Controls> in TabIndex order

I have a windows form that just exists to take input from user, for all intents and purposes it is just a label and a corresponding input box (textbox, checkbox, masket textbox etc).
I have programatically placed all the input fields in a TabIndex order that is optimal for cycling through them in a way that fits with their locations (tab down each column of inputs, then to the top of the next column).
The person that I am building this project for has stipulated that only like each textbox to come available one at a time, as the previous one has been filled out. This is a crude way of doing it with no validation, but essentially something like this...
if (String.IsNullOrEmpty(textbox1.Text))
{
textbox2.Enabled = true
}
So this is fine to do with two textboxes in this example, but the form has 28 different inputs on it, so an absurd series of if statements will only be a last resort.
My thoughts has been to put all the inputs in a List, ideally in the same order as is their TabIndexes. I tried to do this using a foreach loop...
List<Control> inputsList = new List<Control>();
public void initialiseControls()
{
//control position to insert control into list at specified index
int cntrlpos = 0;
//for every control in form
foreach (Control cntrl in this.Controls)
{
//not counting labels (not input fields)
if (!(cntrl is Label))
{
//set list position to equal control's TabIndex
cntrlpos = cntrl.TabIndex;
//insert the control into the list at the position reflecting TabIndex
inputsList.Insert(cntrlpos, cntrl); //<---- Error Occurs
//ASK TEXTBOX TO OUTPUT LIST POSITION AS TEST
//foreach (var txtbx in this.Controls.OfType<TextBox>())
//{
// txtbx.Text = Convert.ToString(cntrlpos);
//}
}
}
As soon as the function is called, an exception is thrown stating that "Index must be within the bounds of the list".
When I put a breakpoint into the code, it showed cntrlpos to equal 29, which is more than the 28 total input controls there are on the form.
I don't know where to go from here, if anyone can offer some advice on the code above to place the Controls into the list in the correct order (or point me in the direction of another method to do something like this), then I would really appreciate it.
Thanks,
Mark
To make your list, try this:
List<Control> inputList =
(from Control c in getAllControls(this)
where c.TabStop
orderby c.TabIndex
select c).ToList();
Define the method getAllControls elsewhere in your form class:
IEnumerable<Control> getAllControls(Control parent)
{
foreach (Control control in parent.Controls)
{
yield return control;
foreach (Control descendant in getAllControls(control))
yield return descendant;
}
}
(Taken and modified slightly from Recursive control search with Linq)
This will make it so that you get even nested controls (such as those in panels or groupboxes).
You can't just use the TabIndex as an index into your list, because even stuff like labels have tab indices, which will mess up your indices.
I think you've over complicated it...
Just use Control.GetNextControl:
Retrieves the next control forward or back in the tab order of child
controls.
For example, with just TextBoxes:
private void textBoxes_TextChanged(object sender, EventArgs e)
{
Control ctl = (Control)sender;
if (!String.IsNullOrEmpty(ctl.Text))
{
Control next = this.GetNextControl(ctl, true);
if (next != null)
{
next.Enabled = true;
}
}
}
Obviously you might need a slightly more complicated check for some other types of controls in a different handler, but you'd still just grab the next control to enable using GetNextControl().

Get source of event in C# Windows Forms

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)
{
...
}

How do you disable a WPF ListViewItem in C# code?

I'm used to the old Winforms way of doing things. Apparently WPF ListViews are full of... XmlElements? How would I do something like disabling a ListViewItem?
foreach (XmlElement item in this.lvwSourceFiles.Items)
{
//disable?
}
ListView is an ItemsControl. ItemsControl.Items does not return the child controls - it returns the items - that is, objects that you have added to the ListView, either directly, or via data binding. I guess in this case you have bound your ListView to some XML, right?
ListViewItem (and other classes like it - e.g. ListBoxItem for ListBox) is called an "item container". To retrieve an item container for a given item, you should do this:
ListView lv;
...
foreach (object item in lv.Items)
{
ListViewItem lvi = (ListViewItem)lv.ItemContainerGenerator.ContainerFromItem(item);
}
You need to access the ListViewItem that represents the data item. You can achieve that through the ItemContainerGenerator
foreach (object item in this.lvwSourceFiles.Items)
{
UIElement ui = lvwSourceFiles.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (ui != null)
ui.IsEnabled = false;
}
You can Perform that In XAML Easily

Categories

Resources