简体   繁体   English

在ToolStrip上发布数据绑定控件

[英]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="". ...我在窗体上使用Text =“”得到一个CheckBox。 I was expecting the Text to be "Hello World!". 我期望文本是“ Hello World!”。 Foo is a public class within Form1 and Foo.Bar is a property with a public get and public set, btw. Foo是Form1中的公共类,而Foo.Bar是具有公共属性btw的属性。 What am I not understanding? 我不明白什么?

::Updated:: The code above actually works. ::更新::上面的代码实际上有效。 The issue only occurs when the CheckBox is on a ToolStrip. 仅当CheckBox位于ToolStrip上时,才会出现此问题。 See below for a real example of the issue. 有关此问题的真实示例,请参见下文。

Thanks. 谢谢。

I had the same problem with binding to a dynamically created ToolStripTextBox. 绑定到动态创建的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. 我需要一个类来托管基于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. 在我的课程中,我将BindingContext对象从宿主窗体传递到构造函数中,并将其分配给弹出窗口。

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). 其次,与ToolStripTextBox关联的TextBox控件不会在创建ToolStripTextBox的同时创建(对于动态创建的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. 我没有执行建议的Show()/ Hide()操作来强制创建TextBox控件,而是调用TextBox控件的CreateControl()方法来强制创建它。 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. 首先,附加到“ ToolStripDropDownButton”的“ ToolStripTextBox”可能尚未真正创建(句柄等),但是当我们添加数据绑定时。 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. 另一方面,对于直接附加到“ ToolStrip”的“ ToolStipTextBox”,它始终在UI上可见,因此可以确定创建。 To workaround this, we can use the following code to force the creation of the “TextBox” control before adding databinding. 要解决此问题,我们可以使用以下代码在添加数据绑定之前强制创建“ TextBox”控件。

      this.toolStripDropDownButton1.ShowDropDown(); this.toolStripDropDownButton1.HideDropDown(); 
  2. Secondly, if we attach the “ToolStripTextBox” to a “ToolStripDropDownButton”, its parent chain is broken. 其次,如果将“ ToolStripTextBox”附加到“ ToolStripDropDownButton”,则其父链断开。 You can see “toolStipTextBox1.TextBox.Parent” is “System.Windows.Forms.ToolStripDropDownMenu” and its grandparent (eg “toolStipTextBox1.TextBox.Parent.Parent”) is null. 您可以看到“ toolStipTextBox1.TextBox.Parent”为“ System.Windows.Forms.ToolStripDropDownMenu”,其祖父母(例如“ toolStipTextBox1.TextBox.Parent.Parent”)为空。 Since the parent chain is broken, the TextBox.BindingContext can no longer refer to the existing BindingContext defined in the main form. 由于父链已断开,因此TextBox.BindingContext不再引用主窗体中定义的现有BindingContext。 Hence we need to create its own BindingContext: 因此,我们需要创建自己的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! 非常感谢Quibblesome! I can replace the foreach in my example to the one below and it works as expected. 我可以将示例中的foreach替换为以下示例,它可以按预期工作。 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. 我可以避免使用DataBinding,而可以将System.Reflection用作解决方法,但是我真的很想知道为什么我的第一个解决方案无法正常工作。

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; }

                }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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