How to copy MenuItem from one ContextMenu to another ContextMenu - c#

How do I copy a MenuItem I created in one ContextMenu and copy it so that I can use it in a second ContextMenu?
I tried to copy it directly and removing it, but I get Element already has a logical parent. It must be detached from the old parent before it is attached to a new one.
foreach(MenuItem mi in menuOptions.Items) {
entityRightClick.Items.Add(mi);
menuOptions.Items.Remove(mi);
}
I tried grabbing the MenuItem using the ItemContainerGenerator, it gave me a blank MenuItem (Debugger says that it is null)
for(int i = 0; i < menuOptions.Items.Count; i++) {
MenuItem temp = new MenuItem();
temp = menuOptions.ItemContainerGenerator.ContainerFromIndex(i) as MenuItem;
entityRightClick.Items.Add(temp);
}

Based on your error message, I'd expect this to work (though I haven't tested it):
foreach(MenuItem mi in menuOptions.Items)
{
menuOptions.Items.Remove(mi);
entityRightClick.Items.Add(mi);
}

Related

Control is removed from old parent control but not if i use a List<Control>, why?

It's probably a very basic question about the behaviour of C# and WebControl. I got this working, but it would be nice if someone could clarify where the difference lays.
Before
I have a dictionary with a given key (Guid) and a Panel.
var tmpFormButtonPanel = new Panel();
_formButtonPanelDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonPanel);
This panel contains a WebControl. Now I'd like to assign this button to another panel.
if (tmpFormButtonPanel != null)
{
var tmpControls = new List<Button>();
foreach (Button tmpButton in tmpFormButtonPanel.Controls)
{
tmpControls.Add(tmpButton);
}
tmpControls.Reverse();
foreach (var tmpButton in tmpControls)
{
tmpButton.AddCssClass("xy");
_buttonPanel.Controls.Add(tmpButton);
}
}
The moment I add the button to the _buttonPanel, it deletes the button out of tmpFormButtonPanel. From what I've heard or read, a WebControl can only be assigned to one panel. So this would explain why it doesn't work.
So I changed the code to this.
var tmpFormButtonList = new List<ButtonBaseUc>();
if (!_formButtonDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonList))
{
tmpFormButtonList = new List<ButtonBaseUc>();
_formButtonDict.Add(new Guid(_hiddenField.Value), tmpFormButtonList);
}
foreach (var tmpButton in tmpFormButtonPanel.Controls)
{
if (tmpButton is ButtonBaseUc)
{
tmpFormButtonList.Add((ButtonBaseUc)tmpButton);
}
}
The last part does the same thing, but on the tmpFormButtonList.
if (tmpFormButtonList!= null)
{
var tmpControls = new List<Button>();
foreach (Button tmpButton in tmpFormButtonList)
{
tmpControls.Add(tmpButton);
}
tmpControls.Reverse();
foreach (var tmpButton in tmpControls)
{
tmpButton.AddCssClass("xy");
_buttonPanel.Controls.Add(tmpButton);
}
}
This is working. But why? I am only assigning the button to another list before adding it to the new panel. The references are still the same. What am I missing?
A control can only belong to one parent control. Since you have assigned it to the Panel in the dictionary-value, it will be removed there if you move it to the _buttonPanel.
This isn't documented but you can see it in the source:
// ...
if (control._parent != null) {
control._parent.Controls.Remove(control);
}
You have fixed this by not using a Panel as "storage" but a List<ButtonBaseUc>. This list is not a control(so the control has no parent), hence it must not be removed if you assign it to another (parent-)control.

Finding and Creating Sub Menus Dynamically

I have a ToolStripMenuItem I need to check if it has a sub menu with a particular name, if it exists, add a new menu item to that sub menu, and if not, create the sub menu and add the item to the new sub menu.
ToolStripItemCollection menu = tsmi1.DropDownItems;
for(int i = 0; i < menu.Count; i++) {
if(item.Category.Equals(menu[i].Text)) {
menu[i]. //need to add new menu item here....
}
}
It may just be that I don't understand how the menu system actually works, but it appears I can't add an item to my menu object.
Is your sub-menu a ToolStripDropDownItem?
The objects in TooLStripItemCollection are all of type ToolStripItem. You may need to cast the item you find to the derived class, ToolStripDropDownItem.
That will give you access to its DropDownItems collection, which is another ToolStripItemCollection and has Add, AddRange, and Insert methods.
I haven't worked with ToolStripDropDownItem myself, but that's the path I'd start on.
Edit by bwoogie:
Final code:
ToolStripMenuItem tsmi = new ToolStripMenuItem();
tsmi.Text = item.Name;
tsmi.Click += node_Click;
ToolStripItemCollection nodeMenu = nodesToolStripMenuItem.DropDownItems;
for (int i = 0; i < nodeMenu.Count; i++) {
if (item.Category.Equals(nodeMenu[i].Text)) {
((ToolStripMenuItem)nodeMenu[i]).DropDownItems.Add(tsmi);
} else {
ToolStripItem newtsi = nodeMenu.Add(item.Category);
((ToolStripMenuItem)newtsi).DropDownItems.Add(tsmi);
}
}

Adding menu items during runtime in C#

I'm still working on getting a menu to display all of the input devices on a computer- pardon my third question in something that is probably very simple.
Here's the code:
List<MenuItem> inputDevice = new List<MenuItem>();
MenuItem myMenuItemInputDevices = new MenuItem("&Input Devices");
sgFileMenu.MenuItems.Add(myMenuItemInputDevice);
for (int i = 0; i < DeviceCount; i++)
{
inputDeviceMenu.Add(new MenuItem(inputName[i]));
myMenuItemInputDevices.MenuItems.Add(inputDeviceMenu[i]);
myMenuItemInputDevices.Click += new System.EventHandler(this.myMenuItemInputDeviceClick);
}
This seems to work just fine, the menu items are added, everything is good, but clicks on the dropdown list are not working. I've done other work with menus, and clicks in other code are working correctly. I tried putting
myMenuItemInputDevices.Click += new System.EventHandler(this.myMenuItemInputDeviceClick);
outside of the {}, just in case that was the right way to do it, but that didn't help.
What am I missing?
You want this
List<MenuItem> inputDevice = new List<MenuItem>();
MenuItem myMenuItemInputDevices = new MenuItem("&Input Devices");
sgFileMenu.MenuItems.Add(myMenuItemInputDevice);
for (int i = 0; i < DeviceCount; i++)
{
inputDeviceMenu.Add(new MenuItem(inputName[i]));
inputDeviceMenu[i].Click += new System.EventHandler(this.myMenuItemInputDeviceClick);
myMenuItemInputDevices.MenuItems.Add(inputDeviceMenu[i]);
myMenuItemInputDevices.Click += new System.EventHandler(this.myMenuItemInputDeviceClick);
}
EDIT: It is pretty obvious that the Menu Items that you are trying to add does not have any Click event method hooked up.
inputDeviceMenu.Add(new MenuItem(inputName[i]));
You are just adding them.

Setting current tab dynamically WPF

I'm working on some feature for my IDE, clicking some treeviewitem, will change the current displayed tab. I'm trying to do that, but no luck. What am I doing wrong?
How can I set the desired tab to be focued?
Here's the code:
void tr_ViewOtherClass(object sender, MouseButtonEventArgs e)
{
string tagToView = ((TreeViewItem) sender).Tag.ToString();
TabItem currentTab = ((TabItem) (tabControl.SelectedItem));
if (tagToView != currentTab.Tag.ToString())
{
TabItem tabToView = null;
for (int i = 0; i < tabControl.Items.Count; i++)
{
tabToView = ((TabItem) (tabControl.Items[i]));
if (tabToView.Tag.ToString() == tagToView)
break;
}
classCodes[currentTab.Tag.ToString()] = ((TextEditor) currentTab.Content).Text;
currentTab = tabToView;
}
}
When you assign a value to the currentTab variable, it does not modify tabControl.SelectedItem.
You must assign directly tabControl.SelectedItem if you want to change its value ; currentTab is equivalent to a pointer, and modifying its value only modifies the value pointed by the local variable.
TabItem currentTab
and
TabItem tabToView
Are each just local variables.
You need to have tabControl SelectedItem bound two way with notify if you want to push the change to the UI.
TabControl behaves differently in MVVM.
I gave the non MVVM way.
MVVM is probably a better way to go for this.

C# WPF i can't enter foreach loop!

I am creating an application with C# WPF:
I have have dynamically generated treeview
In that treeview I have a TreeViewItem called BoekenLijst.
There I generate dynamic TreeViewItems like "the hobbit". The book content, like "the hobbit", I store in the Content property of a Checkbox.
So the treeview will look like this:
Treeview>
TreeViewItem(BoekenLijst)>
The Hobbit
Code Complete
I want to put the checked TreeViewItems in a ListBox so I did the following:
private List<TreeViewItem> GetAllItemContainers(TreeViewItem itemsControl)
{
List<TreeViewItem> allItems = new List<TreeViewItem>();
for (int i = 0; i < itemsControl.Items.Count; i++)
{
// try to get the item Container
TreeViewItem childItemContainer = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem;
// the item container maybe null if it is still not generated from the runtime
if (childItemContainer != null)
{
allItems.Add(childItemContainer);
List<TreeViewItem> childItems = GetAllItemContainers(childItemContainer);
foreach (TreeViewItem childItem in childItems)
{
CheckBox checkBoxTemp = childItem.Header as CheckBox;
if (checkBoxTemp != null)
optieListBox.Items.Add(checkBoxTemp.Content);
allItems.Add(childItem);
}
}
}
return allItems;
}
The problem is, it won't go into: foreach (TreeViewItem childItem in childItems)
Can someone help me out?
Have you tried running it through the Visual Studio debugger? If you insert the break point where the error is getting thrown, then you should be able to get a stack trace of what's going on, and if it's anything like the Eclipse debugger (I've not used VS in a while) you should be able to click on any variable in the code or hold the mouse over it, and it will display the current value of that variable in memory.
But I echo what the others say, try and figure out for yourself, take your time, and work through it step by step. I had to learn that myself, and I still get it wrong as I always forget to use the debugger...ask my team leader if you don't believe me :-)
Welshboy

Categories