简体   繁体   中英

Issue DataBinding Controls on a ToolStrip

After this code...

var cb = new CheckBox();
var b = new Binding("Text", new Form1.Foo() { Bar = "Hello World!" }, "Bar");
cb.DataBindings.Add(b);
AddCheckBoxToForm(cb);

...I get a CheckBox on my Form with Text="". I was expecting the Text to be "Hello World!". Foo is a public class within Form1 and Foo.Bar is a property with a public get and public set, btw. What am I not understanding?

::Updated:: The code above actually works. The issue only occurs when the CheckBox is on a ToolStrip. See below for a real example of the issue.

Thanks.

I had the same problem with binding to a dynamically created ToolStripTextBox. My solution is a little different than the ones already posted here, and I think a little simpler.

I needed a class to host dynamically-created popups based on ContextMenuStrip. I've included the relevant portions below.

As quibblesome indicates, there are two issues involved with doing this. First, you must manually associate a binding context with the popup object. In my class, I am passing the BindingContext object from the host form into my constructor, and assigning that to the popup.

Second, the TextBox control associated with the ToolStripTextBox is not created at the same time the ToolStripTextBox is created (this will also be true of dynamically-created ToolStripDropdowns). Rather than performing the suggested Show()/Hide() operation to force the creation of the TextBox control, I call the CreateControl() method of the TextBox control to force it to be created. Doing it that way seems a little cleaner to me.

public class DevicePopup
{
    ContextMenuStrip    m_popup;

    public DevicePopup(BindingContext bindingContext)
    {
        m_popup = new ContextMenuStrip();
        m_popup.BindingContext = bindingContext;

        . . .
    }

    public ToolStripTextBox AddTextBox(object dataSource, string dataProperty)
    {
      ToolStripTextBox textBox = new ToolStripTextBox();
      textBox.Control.CreateControl();
      textBox.TextBox.DataBindings.Add("Text", dataSource, dataProperty);

      . . . 
      return textBox;
    }
}

I think I may have found your issue. The solution is already effectively summarised in the first response to this thread.

For posterity:

There are 2 difficulties here:

  1. First of all, the “ToolStripTextBox” attached to “ToolStripDropDownButton” may not be truly created (handles and so on) yet when we add the data binding. Data binding here will only work here if the control is already created. The control will usually be created when it is displayed. On the other hand, for a “ToolStipTextBox” attached to the “ToolStrip” directly, it is always visible on UI and hence it is surely created. To workaround this, we can use the following code to force the creation of the “TextBox” control before adding databinding.

      this.toolStripDropDownButton1.ShowDropDown(); this.toolStripDropDownButton1.HideDropDown(); 
  2. Secondly, if we attach the “ToolStripTextBox” to a “ToolStripDropDownButton”, its parent chain is broken. You can see “toolStipTextBox1.TextBox.Parent” is “System.Windows.Forms.ToolStripDropDownMenu” and its grandparent (eg “toolStipTextBox1.TextBox.Parent.Parent”) is null. Since the parent chain is broken, the TextBox.BindingContext can no longer refer to the existing BindingContext defined in the main form. Hence we need to create its own BindingContext:

      this.toolStripTextBox1.TextBox.BindingContext = new BindingContext(); 

So you can try the following code in complete:

  this.toolStripDropDownButton1.ShowDropDown(); this.toolStripDropDownButton1.HideDropDown(); this.toolStripTextBox1.TextBox.BindingContext = new BindingContext(); this.toolStripTextBox1.TextBox.DataBindings.Add("Text", TableClass.get_TBA().DefaultView, "ID"); 

Thank you so much Quibblesome! I can replace the foreach in my example to the one below and it works as expected. Very nice.

        foreach (var item in list)
        {
            var cb = new CheckBox();
            dropDown.AddControl(cb);

            var b = new Binding("Text", item, "text");
            cb.HandleCreated += delegate(object sender, EventArgs e)
            {
                cb.BindingContext = new BindingContext();
                cb.DataBindings.Add(b);
            };
        }

I can avoid DataBinding and use System.Reflection as a work-around, but I would really like to know why my first solution is not working.

This works:

                foreach (var item in ilist)
                {
                    var cb = new CheckBox();
                    cb.Tag = item;
                    _dropDown.AddControl(cb);

                    //* Todo: Could not get binding to work
                    //var b = new Binding("Text", item, this.DisplayMember);
                    //cb.DataBindings.Add(b);
                    try
                    {
                        cb.Text = item.GetType()
                            .GetProperty(this.DisplayMember ?? string.Empty)
                            .GetValue(item, new object[] { }).ToString();
                    }
                    catch { cb.Text = string.Empty; }

                }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM