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.
Related
I have two Forms ( Form_Graph(Main Form), Form_Setting) and one Setting file. When I click on the Setting button, Form_Setting is opened using ShowDialog().
Form_Setting Contains three buttons OK, Cancel, Apply and setting option. Now the problem is when I change Setting and update setting file and after Click on Apply button, I'm not able to apply this setting to Form_Graph.
(Apply_OnClick saves the new setting in setting files.)
I have tried to refresh Form_Graph using:
Form_Graph obj = new Form_Graph();
Application.OpenForms["Form_Graph"].Refresh();
And also I have debugged it. All Form_Graph code is executing on both the way but hasn't applied the settings.
I know the first way never works because I created one new Form, but what about the second one?
Can anyone have a solution for this?
You don't need to create a new instance of parent in child. The best way to do this normally is to subscribe to events from the child form i.e. Form_Setting. You will need to create an event in the child form as follows:
public event EventHandler SettingsApplied;
public void NotifySettingsApplied(EventArgs e)
{
if(SettingsApplied != null)
SettingsApplied(this, e);
}
public void Apply_OnClick(object sender, EventArgs e)
{
//trigger event here to notify main form
NotifySettingsApplied(e);
}
Then in your parent form, subscribe to this event in the constructor or any other suitable place:
public Form_Graph()
{
fs = new Form_Setting();
fs.SettingsApplied += new EventHandler(fs_SettingsApplied);
}
void fs_SettingsApplied(object sender, EventArgs e)
{
//update your main graph form here
}
All i need to write code on Apply_OnClick
// Get Form_Graph object
Form_Graph objGraph = (Form_Graph)Application.OpenForms["Form_Graph"];
// Create a method in Form_Graph class which apply all setting to components
objGraph.UpdateGraph();
// Now refresh Form_Graph
objGraph.Refresh();
Based on your description and comments, you'll need to reload your form for the colors and graphics. You can do it in one of the 3 ways:
Call InitializeComponent() after you return from your settings dialog. This might be dangerous because InitializeComponent() will do other startup stuff too.
Reload your main form too after returning from settings dialog. You may or may not be able to do that based on the state of your main form.
Collect all the code that updates colors and graphics from InitializeComponent() and move it into a separate function. Call it after InitializeComponent() as well as when returning from your settings dialog.
I think the 3rd one would be the cleanest approach.
Edit
Another and generally much more clean way of doing this is through the use of Application Settings. You just go to your form designer, select your control and choose Application Settings from Properties window. Choose the property that you want to bind to a setting and then choose the corresponding setting from the dropdown. If the setting doesn't already exist, you just click the New button and the designer creates one for you.
These settings automatically get loaded and saved for you. No more manual stuff.
Edit 2
For immediate propagation of settings into control properties, you may need to change the default update event when binding your to your setting. To do that, go to your designer file and look for property binding statements:
this.TextBox1.DataBindings.Add("Text", Project1.Properties.Settings.Default.UserName, ""))
and set them to update immediately upon property change:
this.TextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", global::Project1.Properties.Settings.Default, "UserName", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
Actually on a WinForms project (VS 2010, C#, .NET 4.5), I build a matrix (10x10) in a form. Each element is represented by a control that can be "checked" or "unchecked". Each element's state is completely independent of another.
The ideal solution would be to use a CheckBox. Unfortunately, the client wants a different appearance - for example, the one of the RadioButton. I could use RadioButton, place every one of them in a dedicated group, add an event listener to uncheck on-click if the element is already checked... Pretty much for a question of appearance!
Couldn't I override some rendering methods of CheckBox class? (Anyway, that's the only place in the whole application where I use this control)
Note: Controls are instanciated on runtime from a class MyClass:CheckBox.
Use a RadioButton if you need to make it look like one. You'll need to set their AutoCheck property to False to make them act like check boxes and give them a common event handler:
private void radioButtons_Click(object sender, EventArgs e) {
var button = (RadioButton)sender;
button.Checked = !button.Checked;
}
Never hesitate to point out that this is very poor UI design.
I'm refactoring a body of code, looking through it all, line by line.
I came across an event handler:
private void mnuUpdate_Click(object sender, EventArgs e)
...and, not recognizing which menu item called this (the menu item names do not always match their labels, or even come close), was curious.
The main menu on the form has no such menu item among its children.
I r-clicked the event handler, selected "Find Usages*" and was led here:
this.mnuUpdate.Text = "Update";
this.mnuUpdate.Click += new System.EventHandler(this.mnuUpdate_Click);
(This is an antedeluvial app that predates .NET's partial class goodness, so this is in the same file)
On the form in the designer, when I select "mnuUpdate" from the properties page combobox, the mainMenu on the form disappears altogether.
How can I track down this fugitive menu item? There is no popupMenu or contextMenu on the form, just the mainMenu control...???
The only other usage is:
if (ResetConnectionFetchForm)
mnuUpdate_Click(sender, e);
Is it possible that this is simply a phantom menu item that should be converted into a "regular old" method?
UPDATE
As the most intelligent George used to say, "Curiouser and Curiouser." Now I find this:
public void btnCancel_Click(object sender, EventArgs e)
...and though it is called from seven places in the code, there is no btnCancel on the form...It is a "fake" button click event. Oh my Lanta!!!
So, I replaced it with a parameterless private method with the exact same code (it didn't use either sender or event args).
If the cat who wrote this cockamamie glob of fruitcake-battered spaghetti was deliberately trying to drive the next cat (me) crazy, it's working pretty well, and would make a good Poe-style story or Hitchcock-style flick.
...I see...Dead Code!!!
Okay, mystery solved. mnuUpdate is dynamically added (conditionally) to mnuSetup (which is a top level menu item with the Text property "Fetch") like so:
if (!mnuSetup.MenuItems.Contains(mnuUpdate))
{
mnuSetup.MenuItems.Add(mnuUpdate);
UpdateMenuItemSelectable = true;
}
I reckon selecting mnuUpdate from the combobox in the form's Properties page is because there is no visual representation to show at that point.
Selecting "mnuSetup" highlights the "Fetch" menu item, but selecting "mnuUpdate" causes it all to scurry away faster than cockroaches from the light.
So the bizarre thing about it now is: why is the menu item not dynamically created as necessary, instead of being explicitly created and then dynamically added; seems like a strange way for a cat to skin a cat.
I'd suggest you turn it into "regular old menu" so someone else doesn't waste time figuring it out.
Me - I would have thought it obsolete code because it doesn't have a Handles clause.
You can use .Visible and .Enabled to control what the user sees.
I am sure that the answer to this has been posted before. Forgive me as I think I am just not thinking of the right search string.
What I have is a context menu strip assigned to my tray icon for my dialer. The idea is for the user to set various numbers and select the user defined numbers from the menu and initiate the dial.
So the menu pops up with Presets, Setup, & Exit. I want the Presets menu to open a new tree listing the user defined number. I also want this to populate from an xml file every time the application is loaded.
My problem is that I have no idea how to dynamically populate a sub menu item and give it a function.
So how would I at start up add user defined numbers to preset -> (userNumber1, usernumber2, userNumber3) and then call the dial() function when clicked?
So I found how to add to the list... I now feel silly for asking that. For anyone else who wants to know that one, The list item is given a name. Im my case the name attribute is " presetsToolStripMenuItem"
So to add an item to it call the name
presetsToolStripMenuItem.DropDownItems.Add(string text)
No to move on. I am stuck now trying to figure out how to assign an event to that newly added function. I did find
presetsToolStripMenuItem.DropDownItems.Add(string text, image, eventargs)
I am struggling with this one. Maybe I need to stop and come back to it later. Perhaps if someone could provide me with an example of using this line to call a function(); I would be most appreciative.
For anyone that is interested I figured out the solution to adding a context menu item at run time with the ability to call a function.
As stated before, to add a sub menu item to a a parent category, use the parent.name. So in my case the preset menu item name was "presetsToolStripMenuItem"
To add function I used the 3 argument method.
ToolStripMenuItem.DropdownItems.Add("string name", image, eventargs);
so my code looks like this:
presetsToolStripMenuItem.DropDownItems.Add("added2", null, disp);
void disp(object sender, EventArgs e)
{
MessageBox.Show("It works!");
}
I have an AutoCompleteBox binded to an ObservableCollection ItemsSource which I filter on my own by querying entities from a domainservice.
I used the scenario of populating from a webservice call from the blog of Jeff Wilcox, by setting the PopulatingEventArgs.Cancel to True, and when my collection is ready, I call PopulateComplete() on the ACB.
My goal is to reopen the dropdown on mouseover (or click) but without reloading again all the data from the web. I found a question on stackoverflow where the answer was to set IsDropDownOpen to True. But in this case, the ACB population starts again, and another call goes to the webservice.
Of course, when the user starts typing, the filtering should be done again.
(for ex. you type "ric" and the box suggests "rice" and "ricin", you select rice, but you change your mind and want to select another one from the same collection, lets say "ricin". In this case you already have the suggestions containing "ric" in memory, no need to load them again..)
I found an alternative way in which instead of setting IsDropDownOpen, I just simply call the PopulateComplete() method. This does exactly the same thing that I want, but with a little fail: after my ACB loses focus, the dropdown is not opened again on mouseover liek it should. Even when I click back into the acb textbox.
So is there a fix for this, or does someone know why the PopulateComplete() only reopens the dropdown when the ACB has focus for the first time? Or this was only my luck that calling this method reopened the dropdown and the IsDropDownOpen property should be used instead (afaik this would be only possible with some flags indicating that its a fake populating event triggered by my mouseover and after PopulatingEventArgs.Cancel i should call immediately PopulateComplete. but i dont get it, if this may work (haven't tried yet), why not when calling simply the PopulateComplete)?
Well, I tried the IsDropDownOpen with a testing bit, and almost worked:
private void FoodBox_MouseEnter(object sender, MouseEventArgs e)
{
//FoodBox.PopulateComplete(); not working after acb loses focus...
testbit = true;
FoodBox.IsDropDownOpen = true;
}
Here's the overloaded Populating method (no need for setting ItemsSource explicit because its bound to an ObservableCollection):
public void FoodBox_Populating(object sender, PopulatingEventArgs e)
{
e.Cancel = true;
if (!testbit)
{
VM.LoadFoodSuggestions(FoodBox.SearchText);
}
else
{
testbit = false;
FoodBox.PopulateComplete();
}
}
This works good so far, execpt that the search does not start because when (for the first time) you mouseover and select the acb, it sets the testbit to true.
So I added another event handler that takes care of setting the testbit to false every time the user inputs text on the keyboard, ensuring that the suggestions are regenerated/reloaded after SearchText is modified by the user, but not when you select an item from the dropdown:
private void FoodBox_TextChanged(object sender, RoutedEventArgs e)
{
testbit = false;
}
I still don't know why calling PopulateComplete() isn't enough without setting the IsDropDownOpen to Ture, and setting that to true, also delays the dropdown opening approximately with the time specified in the MinimumPopulateDelay, but at least it gives me the functionality I wanted. (Maybe digging into the source of acb would answer this mistery)
Maybe this functionality implemented in the basic acb would be helpful in a future release of the control.