In my Winforms application I have a ToolStripMenuItem with nested sub-items, the structure of which is shown below.
File
.+...Add As....+.....File
............................Folder
............................Root Folder
Under 'Add As' I want to be able to programmatically enable and disable 'File', 'Folder', and 'Root Folder' as required. How can I access these nested items in code?
I have tried ToolStripMenuItem.DropDownItems[0].Enabled = true\false; but this affects 'Add As' and everything below it in the menu hiearachy.
If I use an index greater than zero in the code above I get an 'index out of range' error. How do I go about achieving this functionality?
Simply reference the sub-items by their own names eg:
FileToolStripMenuItem.Enabled = false;
FolderToolStripMenuItem.Enabled = false;
RootFolderToolStripMenuItem.Enabled = false;
Unless I'm missing something, this seems like the simplest answer.
As Hans' hinted in his comment, you are referencing the wrong DropDownItems collection.
To do this using indexes will get ugly quickly.
It's simpler to just reference the parent menu and loop through "its" menu collection:
private void toggleMenu_Click(object sender, EventArgs e) {
foreach (ToolStripMenuItem toolItem in addAsToolStripMenuItem.DropDownItems) {
toolItem.Enabled = !toolItem.Enabled;
}
}
Here is the ugly method, which would be difficult to maintain if you decided later to rearrange your menu structure:
foreach (ToolStripMenuItem toolItem in ((ToolStripMenuItem)((ToolStripMenuItem)menuStrip1.Items[0]).DropDownItems[0]).DropDownItems) {
toolItem.Enabled = !toolItem.Enabled;
}
Related
I have a ContextMenuStrip for a right-click context menu. Inside is a ToolStripMenuItem that contains a ToolStripItem array. Inside the array is a dynamically created ToolStripComboBox.
The issue I am having is that I cannot access the meat of the combobox. It has been linking to a databinding through the ComboBox. A general version of the code is below.
myToolStripComboBox.ComboBox.DataSource = enumList;
ToolStripItem[] toolStripItems = new ToolStripItem[1];
toolStripItems[0] = myToolStripComboBox;
ToolStripMenuItem sortOrder = new ToolStripMenuItem("Sorter", null, toolStripItems);
rightClickPopupMenu.Items.Add(sortOrder);
Looking through the debug shows that the datasource is indeed still set and I have all the required values, but the right-click context menu refuses to show anything but a blank combobox.
Try this :
private void chData_MouseMove(object sender, MouseEventArgs e)
{
try
{
//your combobox binding Code
tooltip.SetToolTip(cmdfoo, tipInfo);
}
catch { }
}
This is just a simple example.
Had the local c# wizard at work look at it. Something along the lines of the databinding not being called by a proper parent object.
The solution was to just directly add the times to the combo box items.
dropDown.ComboBox.Items.Add(enum);
So what I have done is make a list of the enum objects and done a foreach to add them all.
I am using the PropertyGrid from the Xceed WPF Extended Toolkit. Is there a way that I can make all properties expanded by default? Actually, I'll never need them to be "unexpanded" ever, so if the "un-expansion" (is there a word for that, BTW?) could be disabled, that would be even better.
If you are still looking for a way to do this, I just figured it out myself.
private void PropertyGrid_SelectedObjectChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var grid = sender as PropertyGrid;
foreach (PropertyItem prop in grid.Properties)
{
if (prop.IsExpandable) //Only expand things marked as Expandable, otherwise it will expand everything possible, such as strings, which you probably don't want.
{
prop.IsExpanded = true; //This will expand the property.
prop.IsExpandable = false; //This will remove the ability to toggle the expanded state.
}
}
}
If you set IsCategorized="False" you will see all properties expanded by default:
<xceed:PropertyGrid IsCategorized="False" SelectedObject="{Binding}"/>
Also you can specify
ShowPreview="False" ShowSearchBox="False" ShowSortOptions="False"
ShowSummary="False" ShowTitle="False" ShowAdvancedOptions="False"
to disable all other parts than main property editor grid.
_propertyGrid.ExpandAllProperties();
I want to implement visual studio style Add or Remove Ruttons toolstrip like following
in my winforms application, how can I achieve this?
I haven't tried anything on this as I am not sure how to start and I don't have much working experience on winforms.
Please suggest.
At first glance it doesn't look all that difficult.
Just add a ToolStripDropDownButton to your ToolStrip with no image or text. That will make the appearance seem more or less similar.
Add to this drop down button one ToolStripMenuItem with a "Add or Remove Buttons" caption. We'll call it AddRemoveMenuItem.
Now populate AddRemoveMenuItem's child menu items with menu items representing all your configurable ToolStripItems. You can link menu item and configurable tool strip item through the menu item's Tag property (you could also subclass ToolStripMenuItem adding a ToolStripItem LinkedToolStripItem { get; set; } property but I don't think its really worth it).
All these "linked" menu items will have to handle their Click events where they will switch their linked tool strip item's Visible property and synchronize their Checked state accordingly.
I'd do that the following way:
linkedMenuItem.Click += (sender, e) => linkedMenuItem.Checked = !linkedMenuItem.Checked;
linkedMenuItem.CheckedChanged +=
(sender, e) =>
{
var linkedToolStripItem = linkedMenuItem.Tag as ToolStripItem;
if (linkedToolStripItem != null)
{
linkedToolStripItem.Visible = linkedMenuItem.Checked;
}
};
When starting up your application set the linked menu items Checked state accordingly to your app's default settings, user settings, etc. and you are done.
I have a ContextMenu with some sub-menus that have items (MenuItem) that can be selected. When the ContextMenu is opened, I want to recursively open the currently selected item. So, I have the following code:
protected override void OnOpened( RoutedEventArgs e ) {
base.OnOpened( e );
OpenCurrentSubMenu( Items );
}
private static bool OpenCurrentSubMenu( ItemCollection itemCollection ) {
foreach (MenuItem item in itemCollection) {
if (item.IsChecked) {
return true;
}
else if( OpenCurrentSubMenu( item.Items ) ) {
item.IsSubmenuOpen = true;
return true;
}
}
return false;
}
I also have some other code that ensures that only one item is checked.
This seems to work great the first time I select an item in a sub-menu. When I re-open the ContextMenu, the open sub-menus cascade open to the selected item:
However, when I leave the context menu, and re-open it a second time, the selected menu does NOT open:
Does anyone know why and how to fix it?
Three things to try:
When the context menu is opened, recurse over the entire hierarchy and set IsSubmenuOpen = false before you try to open any submenus. It may be that the previously open submenu is remembered and thus you're trying to tell it to have two open submenus at the same level.
Recurse to find the submenus that need to be opened and store them in a list. Then iterate through the list and set them so that the topmost menu is set open before its child submenu is set open. (It may be that trying to open the child when its parent is not yet open won't always work reliably).
Nasty brute force approach: Delete and recreate the context menu each time it is opened. It's not nice, but if you're opening a context menu you're likely to be worried about the performance implications. And it appears that it works the first time, so make every time the first time.
It might help to set the value to false before setting it back to true. I can't confirm this though.
item.IsSubmenuOpen = false;
item.IsSubmenuOpen = true;
I think the logic should work well ... when the menu item is checked, but not when sub menu item is checked.
In my opinion try two loops .... one for menu and another one for sub menu items.
None of the solutions works/clear to me and none of them looks elegant.
I found something that works.
Try this:
public partial class WindowWithContextMenu : Window
{
// Add this Show method
public new void Show()
{
base.Show();
base.Activate();
// Do this for any context menu!
MyContextMenu.IsSubmenuOpen = true;
MyContextMenu.IsSubmenuOpen = false;
MyContextMenu2.IsSubmenuOpen = true;
MyContextMenu2.IsSubmenuOpen = false;
// And so on
}
...
...
}
This way you modify a bit the original Show() method of the window.
Now when you call the Show() method, it will run this small hack.
Then at some point, you may click on some button that opens the menus.
The thing is that this time it will always work and not only on the first time!
MyContextMenu and MyContextMenu2 are defined in the XAML file and they are not opened by default in the XAML file.
I have no idea why this works but it did. It is ugly but the hack is simple and a copy-paste solution...
I also found that in order to reproduce the issue, you need to lock the account and log in again. It reproduced by 100% each time I did it.
In my windows application i have a context menu with a grid the problem is that I want to disable the ToolStripMenuItem in context menu according to the user previlages.How can i do that. i have done like this but it is not working
private void contextMenuStrip_Machine_Opening(object sender, CancelEventArgs e)
{
toolStripAuthorize.Enabled = INFOpermission.accessAuthorize;
}
but it is not working
You need to set toolStripAuthorize.Enabled to either true or false.
I have no idea what INFOpermission.accessAuthorize is because you didn't show the code that defines that (enum?), but if it's anything other than false, this isn't going to work out like you expect.
I can guarantee that setting the Enabled property of the ToolStripMenuItem that you want to disable to false in the Opening event handler will work. If it's not working for you, you're doing something else wrong, and you need to give us some more information to go on.
If you're stuck, see the sample code here: How to: Handle the ContextMenuStrip Opening Event
EDIT: Armed with new information provided in the comments, I've now isolated the source of the problem. You've assigned the ContextMenuStrip to the RowTemplate of a DataGridView control, and are therefore not able to modify items contained in that context menu in its Opening event handler method.
It turns out that this is a known bug that someone decided was "by design". You can see the original bug report here on Microsoft Connect. The explanation given is that whenever a new row is created based on the RowTemplate (which is how the RowTemplate works), the ContextMenuStrip that you've assigned gets cloned as well. That means the same context menu instance is not used for each row, and whatever properties that you try to set on the original menu items have no effect.
Fortunately, it also gives us a workaround. Like all events, the Opening event passes the actual instance of the ContextMenuStrip that is about to be opened as its sender parameter. This is the context menu whose items you need to modify in order for your alterations to be visible.
So what's the code? It looks like this:
private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
{
ContextMenuStrip cmnu = (ContextMenuStrip)sender;
cmnu.Items[1].Enabled = false;
}
Notice, though, that you'll have to reference the individual menu item that you want to modify by its index. This is just the zero-based position of the item in the menu that you want to modify. You can't use the toolStripAuthorize object like you were trying to do before because a new instance of it has been cloned for each new context menu instance.