I know this is a bit late in the day, but I have had the same problem - the control I want to bind to is set to visible = false when the form is displayed. I possibly want to do this on a lot of forms and I am always reluctant to write reems of code for each binding.
So I put together a little hack.
I have a form with a panel that I set to Visible = false in the constructor. I want to bind the view to a custom view model I wrote. In the form, I drop in a BindingSource from the Toolbox. I DataSource of the binding source to a Project Data source for my view model.
The idea is then to iterate through the controls on the form, and update the controls bound value from the data source (which is the view model).
To do this, I store the visible value of the control, set it to false, and read the bound value. Then restore the initial visible value. This is done in the aptly named method HackIt().
Here is the code:
ViewModel
public class SimpleViewModel // : DomainModelBase - add your notify property changed
{
public SimpleViewModel()
{
_visible = true;
}
private bool _visible;
public bool Visible
{
get
{
return _visible;
}
set
{
_visible = value;
OnPropertyChanged("Visible");
}
}
}
Form Designer Code
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.panel1 = new System.Windows.Forms.Panel();
this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components);
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).BeginInit();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(0)))));
this.panel1.DataBindings.Add(new System.Windows.Forms.Binding("Visible", this.bindingSource1, "Visible", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.panel1.Location = new System.Drawing.Point(94, 85);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(200, 100);
this.panel1.TabIndex = 0;
//
// bindingSource1
//
this.bindingSource1.DataSource = typeof(WindowsFormsBindVisible.SimpleViewModel);
//
// button1
//
this.button1.Location = new System.Drawing.Point(74, 34);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.Location = new System.Drawing.Point(155, 34);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "button2";
this.button2.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(500, 261);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.BindingSource bindingSource1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
}
Form Code
public partial class Form1 : Form
{
public SimpleViewModel ViewModel = new SimpleViewModel();
public Form1()
{
InitializeComponent();
this.panel1.Visible = false;
this.bindingSource1.DataSource = this.ViewModel;
}
private void Form1_Load(object sender, EventArgs e)
{
HackIt();
}
void HackIt()
{
this.SuspendLayout();
foreach(Control control in this.Controls)
{
var v = control.Visible;
control.Visible = true;
foreach(Binding db in control.DataBindings)
{
db.ReadValue();
}
control.Visible = v;
}
this.ResumeLayout();
}
}
With the above code, the form starts up and shows my control. You can change the view model constructor and default to false to hide. It works either way.
In the form constructor - I want to explicitly hide the panel (this.panel1.Visible = false) - just to prove the binding when view model default visible = true, the control is displayed correctly on load.
We can then make the buttons change the visible on the view model which will toggle the state of the panel visible:
private void button1_Click(object sender, EventArgs e)
{
this.ViewModel.Visible = false;
}
private void button2_Click(object sender, EventArgs e)
{
this.ViewModel.Visible = true;
}
UPDATE
This got me over the first hurdle. However, I am using Telerik components so I decided to drop a Telerik control on the form. That completely broke everything.
Instead of the HackIt method above, call the following RefreshDataBindings() in the load event.
I decided to iterate through all controls on the form and manually update the binding the reflective way. This is crazy! But it works 100% - even with Telerik controls on my form. And the performance is ok in my main application. This is a down right dirty hack - but I put this once in either a base form or base control - and I am not worrying about my bindings.
protected void RefreshDataBindings()
{
foreach (Control control in this.Controls)
RefreshControlBindingsRecursive(control);
}
private void RefreshControlBindingsRecursive(Control control)
{
if (!control.Visible || !control.Created)
{
foreach (Binding db in control.DataBindings)
{
if (db.PropertyName == "Visible")
{
try
{
object dataSource = db.DataSource is BindingSource ?
(db.DataSource as BindingSource).DataSource : db.DataSource;
PropertyInfo pi =
dataSource.GetType().GetProperty(db.BindingMemberInfo.BindingMember); ;
PropertyInfo piC = db.Control.GetType().GetProperty(db.PropertyName);
piC.SetValue(db.Control, pi.GetValue(dataSource));
}
catch (Exception ex)
{
string s = ""; // not bothered its too late at night
}
}
}
}
foreach (Control child in control.Controls)
RefreshControlBindingsRecursive(child);
}