0

I recently came upon what seems to be an oddity of win forms property binding in that if a control starts out life* as invisible, the control doesn't seem to see changes in the bound property. In this case I was binding a label's .Visible property to Properties.Settings.Default.BooleanSetting (default False) in the application settings. I was also binding a checkbox .Checked to the same setting, the idea being that toggling the checkbox to checked would cause the label to appear and unchecked would cause it to disappear. All setup was done in the forms designer

This only worked reliably when the setting was True at application startup. If the setting was False, the checkbox would be unchecked, and the label invisible but checking the checkbox would not show the label. Upon debugging it turned out that the value of the setting was true, so the checkbox had updated it, but the label's Visible property was still false

Other bound properties didn't seem to have a problem if the label was initially visible; Enabled could be bound and would reliably flip state when the checkbox was toggled regardless of the initial value of the setting. The problem seemed to be specifically if the label started out invisible - an invisible label with its Enabled property bound to that boolean wouldn't change Enabled state.

The workaround seemed to be to store Properties.Settings.Default.BooleanSetting, set it to true before calling InitializeComponent() then revert it. In this case the form would show, and checking the box would reveal the invisible label

            var b = Properties.Settings.Default.FormatWithoutConfirmation;
            Properties.Settings.Default.FormatWithoutConfirmation = true;
            InitializeComponent();
            Properties.Settings.Default.FormatWithoutConfirmation = b;

I first drew the conclusion (with some help from a related question here - asking about how to make it work) that a control needs to be initially visible for binding to work, and having a control invisible puts the control in the catch 22 of never being Visible in order to see the change in Visible..

It does seem to be a one time setup thing rather than a "if a control ever goes invisible it stops listening" thing because if it always affected an invisible control then a control that started out visible would go invisible and never return - this isn't the case, and initially visible controls toggle visibility on and off perfectly.

One sticking point for me in the initially-visible theory is that, according to the code in the windows designer, binding happens before the visibility is set:

        this.label4.AutoSize = true;
        this.label4.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", global::Namespace.Properties.Settings.Default, "BooleanSetting", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
        this.label4.Enabled = global::Namespace.Properties.Settings.Default.BooleanSetting;
        this.label4.Location = new System.Drawing.Point(100, 100);
        this.label4.Name = "label4";
        this.label4.Size = new System.Drawing.Size(35, 13);
        this.label4.TabIndex = 11;
        this.label4.Text = "label4";
        this.label4.Visible = false;

At the time binding is set up here, Visibility must be True because that's the default for the Visible property. It seems like there is something else that happens later to finish off the setup, or that there is a critical moment early in a control's life (but not this early) where something happens to it that determines whether it will or won't listen to bound property changes


I get the feeling that the answer might be out there somewhere in MSDN as one of the answers in that question I linked to said...

assume that binding to a control's Visible property is broken, despite the fact that it sometimes works. See http://support.microsoft.com/kb/327305, which says as much

...but the link given to MSDN has rotted. Another related question I read mentioned that initially invisible controls don't have handles when created and mooted it as a possible factor


*not sure when a control's life starts, ref the "visibility is set after binding is created" note

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • Quite likely unless a control has a live `Handle` binding won't work. – RussKie Apr 22 '20 at 07:00
  • If the initial state of a Control visibility is `false`, the handle is not created. This has consequences on property bindings. You can see it here: [CreateControl()](https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,5848). The notes there already explain it. Also, note that the method calls its overload as `CreateControl(false)`, where `false` means *don't ignore visible state*. There you find a comment: *Only "create" the control if it is visible*. If you override `OnHandleCreated` of a custom control, you see it's never called. – Jimi Apr 22 '20 at 09:19

1 Answers1

0

As was suggested, as long as a Windows Forms Control doesn't have a valid Windows Handle, DataBinding will not be active.

I first realized this many years ago when I had to work on a Window with a Tab Control on it. It took me a while to understand why Control on Tabs that were initially invisible would not properly bind, but on the first Tab, all was fine.

Once I understood what the problem was, I wanted to find a nice way to work around it, but at that time, the project leader didn't have the budget. So, I went down the path of laziness, and simply cycled through all Tabs, giving them a chance to be visible very briefly, and all Controls on those Tabs then had the possibility of getting a valid Handle.

It sucked real bad because the Tab pages could be seen flickering during the process. This ended up never being fixed, and the application was released as-is. Needless to say that the other programmers and myself were not too happy about it, but the customer never complained. Go figure.

So, the Control must be visible to get its Handle, and then can be hidden.

Good luck forward.

Luc Morin
  • 5,302
  • 20
  • 39
  • Do you have any comment on the sticking point I mentioned; that at the instant the binding is created in the Designer.cs, the control *is* visible=true.. Is there something that happens later, when the control is visible false? Such as "yes, binding is deferred execution like LINQ; it only happens .... seconds later when the control is ..... and at that moment it is invisible" .. – Caius Jard Jun 10 '20 at 00:14