0

I have encounter that issue a long time ago and again now. I cannot figure out what special thing had to be done to edit the ToolStripMenuItem control a Visible property while inside a form load.

in designer.cs

private System.Windows.Forms.ToolStripMenuItem mnuExport;
// 
// mnuExport
// 
this.mnuExport.Name = "mnuExport";
this.mnuExport.Size = new System.Drawing.Size(116, 22);
this.mnuExport.Text = "Export";
this.mnuExport.Visible = false;
this.mnuExport.Click += new System.EventHandler(this.mnuExport_Click);

in the form code

public partial class MainBuilder : Form
{
    private void MainBuilder_Load(object sender, EventArgs e)
    {
        mnuExport.Visible = true;
    }
}

In the code above export is a menu item of type ToolStripMenuItem which trough the property grid in the form design mode I have modified it's Visible property to false. So in the form load I want to switch to the visible state to true. I thought it be easy so I coded all the logic around and it failed. So I decided to remove all my code and simply hardcode the set to true and to my surprise this does not work.

When I put the breakpoint on the line in the form_load I clearly see it's false and if it let the line run the value is still false.

I recall seeing this issue in the past but cannot find anything about it. I also tried with 4-5 other menu item in that window and they all show the same behavior.

EDIT just tried to put visible = true in the designer.cs instead and in the form_load still tells me the value is false. There is some major issues here.

Franck
  • 4,438
  • 1
  • 28
  • 55
  • 2
    Move the code to the Shown event. Also check whether the Owner is visible. – Jimi Aug 17 '21 at 20:34
  • There might be two reasons. One is that if you put your breakpoint on the line mnuExport.Visible = true; you have to trace with F10 and see if its is still false or not? Another tip is that you have have to find another event to set it after last time it gets false. I suggest create a method with onvisibleChange and make a messagebox or printline to see in which part it changes to false and true, and then you can find that specific location in your code. – Reza Akraminejad Aug 17 '21 at 20:46
  • 2
    @Hamed_gibago ToolStripMenuItem are not usually visible until something *requires their presence* :) I suggested to set the Visible Property in the Shown event so it may become clear what happens when you set that property in a Menu of sort. Check the Owner's value. If you set the Owner's Visible property to `true` and the Owner is a top-level MenuItem... – Jimi Aug 17 '21 at 21:15
  • In your `MainBuilder_Load` event handler your form is not visible. So everything on your form is also not visible. It doesn't make a difference if you set any Visible property to true, it would take an effect only after your form becomes visible. – Steeeve Aug 17 '21 at 21:41
  • @Steeeve Already mentioned: MenuItems are not visible by default. It also depends on the Owner's *visibility* [Notes here](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ToolStripMenuItem.cs,659). The OP should check the `Available` property [Notes here](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ToolStripItem.cs,439), to determine whether the MenuItem will be visible (and participate in the Layout). The `Visible` value is cached and the state set when the Menu is shown on screen. – Jimi Aug 17 '21 at 21:55
  • @Jimi I tried to explain the situation with other words. I hope it's not a problem. – Steeeve Aug 17 '21 at 22:06
  • 1
    @Steeeve It sounds like you're asking a police officer :) It's not up to me to say. I just try to share what I know. To sum it up: The `Visible` property of MenuItems (ToolStripItems) is a compat feature. This is a state that is cached. The property returns: `(ParentInternal!=null) && (ParentInternal.Visible) && Available`. So, the `Available` property is more relevant. All child MenuItems always have their `Visible` property `= false`, at any time except when the Menu is shown on screen. Only a top-level MenuItem (e.g., the owner is a MenuStrip) returns `Visible = true`. – Jimi Aug 17 '21 at 22:58
  • Well I've simulated your situation and I added a menuStrip with multiple toolStripMenuItem and called one of them export. Set export visible to false in form designer but in form_load event set it to true. It shows but after setting breakpoint see that it shows false value for it. Yours shows it too? your question is despite it has false value why it is shown it form? yes? – Reza Akraminejad Aug 18 '21 at 07:04
  • @Hamed_gibago I'm off to test all suggested comments but for yours the answer is no. When the control set to default `true` in the `form_load` it now show `false` and when in `form_load` I set to to `true` it still show the property as false and when the form is shown on screen the menu is still visible false. So the setter of the object does not accept my input. – Franck Aug 18 '21 at 11:31
  • It is the way the Visible property behaves for any control. A bit asymmetric, when you set it to true then you indicate that you'd like it to be visible. But when you read it back then it tells you if the control/item is *actually* visible to the user. It can't be in the Load event handler, not yet, the form isn't visible yet. – Hans Passant Aug 18 '21 at 17:39

1 Answers1

0

As mentioned in the comments the property Visible getter does not reflect the actual inner property value until later in the lifecycle. It is still unavailable in the form_loaded event. My main problem is that one menu visibility state was based on if all sub menus are not visible then it should not either. To do so I was iterating on it's child and checking the Visible property. The problem is them having Visible to false due to the way it works the parent set it's own Visible to false as well.

I don't like the solution but that's the only way to make it work

// get all sub menus
var subMenus = mnuExport.DropDownItems.Cast<ToolStripItem>().ToList();

// create a list of bool that will store the visible state I want the controls to have. put them to true by default
var menusVisibleStates = Enumerable.Repeat(true, menus.Count).ToList();

// set the visibility state of each sub menus
for (int i = 0; i < menus.Count; i++)
{
    // some logic is here that choose true or false but is irrelevant here
    var visibleStateIWant = true; 

    // set the visible state stored
    menusVisibleStates[i] = false;

    // set the actual control value that will change later on
    menus[i].Visible = false;
}

/// now here I use the state I have specified and NOT the menu object property
mnuExport.Visible = menusVisibleStates.Any(o => o);
Franck
  • 4,438
  • 1
  • 28
  • 55