【问题标题】:Issue DataBinding Controls on a ToolStrip在 ToolStrip 上发出 DataBinding 控件
【发布时间】:2011-02-06 03:27:40
【问题描述】:

在这段代码之后...

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

...我的表单上有一个带有 Text="" 的复选框。我期待文本是“Hello World!”。 Foo 是 Form1 中的公共类,而 Foo.Bar 是具有公共获取和公共设置的属性,顺便说一句。我不明白什么?

::Updated:: 上面的代码确实有效。仅当 CheckBox 在 ToolStrip 上时才会出现此问题。有关该问题的真实示例,请参见下文。

谢谢。

【问题讨论】:

    标签: c# .net winforms data-binding


    【解决方案1】:

    我想我可能已经找到了您的问题。该解决方案已经在this线程的第一个响应中得到了有效的总结。

    为了后代:

    这里有两个困难:

    1. 首先,将“ToolStripTextBox”附加到 “ToolStripDropDownButton”可能不是 真正创建(句柄等)尚未 当我们添加数据绑定时。数据 此处绑定仅在以下情况下才有效 控件已经创建。这 控件通常会在何时创建 它被显示。另一方面, 对于附加到的“ToolStipTextBox” “ToolStrip”直接,它总是 在 UI 上可见,因此它肯定是 创建的。为了解决这个问题,我们可以 使用以下代码强制 创建“TextBox”控件 在添加数据绑定之前。

          this.toolStripDropDownButton1.ShowDropDown();
          this.toolStripDropDownButton1.HideDropDown();
      
    2. 其次,如果我们将“ToolStripTextBox”附加到 “ToolStripDropDownButton”,它的父级 链条断了。你可以看到 “toolStipTextBox1.TextBox.Parent”是 “System.Windows.Forms.ToolStripDropDownMenu” 及其祖父母(例如 “toolStipTextBox1.TextBox.Parent.Parent”) 一片空白。由于父链是 坏了,TextBox.BindingContext 可以 不再参考现有的 BindingContext 定义在 main 形式。因此我们需要创建自己的 绑定上下文:

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

    所以你可以完整地尝试下面的代码:

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

    【讨论】:

    • 谢谢!这正是吸引我的原因。
    【解决方案2】:

    非常感谢 Quibblesome!我可以将示例中的 foreach 替换为下面的示例,它可以按预期工作。很不错。

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

    【讨论】:

    • 太好了,我不知道有一个句柄事件被创建了!这看起来很方便。
    • 我也没有,直到我方便为止!显然,您可以通过简单地引用 [Control.Handle][1] 属性来强制创建句柄。这可能是比上述更有效的解决方案。 [1]:msdn.microsoft.com/en-us/library/…
    【解决方案3】:

    我在绑定到动态创建的 ToolStripTextBox 时遇到了同样的问题。我的解决方案与这里已经发布的解决方案略有不同,我认为更简单一些。

    我需要一个类来托管基于 ContextMenuStrip 动态创建的弹出窗口。我已经在下面包含了相关部分。

    正如 quibblesome 所指出的,这样做涉及两个问题。首先,您必须手动将绑定上下文与弹出对象关联。在我的类中,我将 BindingContext 对象从主机表单传递到我的构造函数,并将其分配给弹出窗口。

    其次,与 ToolStripTextBox 关联的 TextBox 控件不是在创建 ToolStripTextBox 的同时创建的(动态创建的 ToolStripDropdowns 也是如此)。我没有执行建议的 Show()/Hide() 操作来强制创建 TextBox 控件,而是调用 TextBox 控件的 CreateControl() 方法来强制创建它。这样做对我来说似乎更干净一些。

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

    【讨论】:

      【解决方案4】:

      我可以避免 DataBinding 并使用 System.Reflection 作为解决方法,但我真的很想知道为什么我的第一个解决方案不起作用。

      这行得通:

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

      【讨论】:

      • 注意我的帖子的更新。创建一个小而完整的示例来展示该问题。不要绕过垃圾的问题,了解问题并解决它。
      • 我昨晚做了那个并用代码更新了我的帖子,我仍然没有看到问题。如果可以,请检查一下。谢谢。
      猜你喜欢
      • 2013-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多