【问题标题】:C# Databound Windows Forms control does not retain value unless you leave the field除非您离开该字段,否则 C# Databound Windows Forms 控件不会保留值
【发布时间】:2011-01-03 21:43:46
【问题描述】:

我在Databound Windows Forms control does not recognize change until losing focus看到了答案。

但这并不能完全回答我的问题。我有完全相同的情况。在 ToolStrip_click 上,我浏览了所有控件并强制执行“WriteValue()”,但它仍会恢复为保存之前的先前值。谁能建议我如何解决这个问题?我是不是错误地实现了这个?

(查看当前(非工作)解决方案的代码。)

private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
    // Make sure that all items have updated databindings.
    foreach (Control C in this.Controls)
    {
        foreach (Binding b in C.DataBindings)
        {
            // Help: this doesn't seem to be working.
            b.WriteValue();
        }
    }
}

代码现在要简单得多,但它是一个相当大的 hack。我很高兴知道是否有更“适当”的解决方法。

private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
    // Make sure that all text fields have updated by forcing everything
    // to lose focus except this lonely little label.
    label44.Focus();
}

【问题讨论】:

    标签: c# winforms data-binding


    【解决方案1】:

    对我来说这是最糟糕的。如果我在组合框上将更新源模式设置为 OnPropertyChanged,它的行为就像我将其设置为 Onvalidation 模式一样! wpf 中的绑定要好得多。

    【讨论】:

      【解决方案2】:

      你要绑定什么?如果是 DataSet、DataTable 等,或者更好的是 BindingSource,则应调用 EndEdit:

      private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
      {
          // Assuming that you are binding to bindingSource1:
          bindingSource1.EndEdit();
      }
      

      我在我的表单上实现了一个ISave 接口来处理脏状态和保存,并且每当检查脏状态(每当调用 IsDirty 时),我总是在我的绑定源上 EndEdit:

      interface ISave
      {
          bool IsDirty;
          bool Save(bool force);
      }
      

      使用这个界面,当应用程序关闭时,我可以轻松地遍历打开的 MdiChild 窗口,通过将子表单转换为 ISave 并检查 @ 的值来检查是否保存了任何信息987654325@。在这里,我在适当的绑定源或(如果适用)绑定控件(例如,网格)上调用 EndEdit。

      请原谅我的啰嗦,但我认为这可能会有所帮助。其余的工作如下:

      Save() 采用“强制”参数,因此我可以在表单中使用“保存并关闭”按钮(为用户节省额外的点击或确认,询问他们是否要保存更改)。如果 force 为 false,Save() 方法负责询问用户是否要保存。如果是真的,则假定用户已经决定他们肯定要保存他们的信息,并跳过此确认。

      Save() 如果可以安全地继续执行调用代码(可能是 Form_Closing 事件),则返回 bool-true。在这种情况下,(如果 force 为假),给定 YesNoCancel 消息框,用户要么选择 Yes 要么 No 并且保存本身没有引发错误。或者,Save() 在用户选择 Cancel 或出现错误(换句话说,告诉调用代码取消表单关闭)的情况下返回 false。

      您如何处理错误取决于您的异常捕获约定 - 这可能在 Save() 方法中被捕获并显示给用户,或者可能在诸如 FormClosing 之类的事件中,其中 e.Cancel 将被设置为 true .

      与表单关闭事件一起使用,它看起来像这样:

      private void form1_FormClosing(object sender, CancelEventArgs e)
      {
          if (IsDirty)
              e.Cancel = !Save(false);
      }
      

      与保存并关闭按钮的强制保存一起使用,它看起来像这样:

      private void btnSaveAndClose_Click(object sender, EventArgs e)
      {
           if (IsDirty)
              if (Save(true))
                  Close();
      }
      

      无论如何,比你要求的多一点,但我希望这会有所帮助!

      【讨论】:

        【解决方案3】:

        问题可能是您的数据绑定控件设置为在验证时更新。

        您需要将每个数据绑定控件的 DataSourceUpdateMode 设置为 DataSourceUpdateMode.OnPropertyChanged。例如,数据绑定文本框:

        this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", 
            this.someBindingSource, "SomeProperty", true, 
            System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
        

        您也可以通过以下方式在设计器中设置数据源更新模式:

        选择控件并进入属性窗口 -> (DataBindings) -> (Advanced)

        -> 将下拉列表中的【数据源更新模式】设置为 OnPropertyChanged。

        干杯

        【讨论】:

        • 就是这样......你不知道这个问题已经让我发疯了多久。谢谢。回想起来似乎很简单,但我问过的所有“专家”,甚至是来自微软的,都被它吓傻了。干得好!
        • "Property Window -> (DataBindings) -> (Advanced)...将下拉列表中的...设置为 OnPropertyChanged..." - OMG 我从来不知道那是在那里!我希望我能投票给你一个 squillion 次好先生! :D
        【解决方案4】:

        这在过去让我很难过。除了将 DataSourceUpdateMode 设置为 OnPropertyChanged 之外,数据源中的基础列不得为只读。

        在 DataTable 中检查您的列:

        dataTable.Columns("ColumnName").ReadOnly

        我什至做了一个函数,将所有列设置为不只读,这已经派上用场不止一次了:

        Public Function MakeReadOnlyFalse(ByVal dt As DataTable) As DataTable
        
            For Each col As DataColumn In dt.Columns
                If col.ReadOnly Then
                    col.ReadOnly = False
                End If
            Next
        
            Return dt
        End Function
        

        【讨论】:

          【解决方案5】:

          试试这个:

          private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
          {
              // Make sure that all items have updated databindings.
              foreach (Control C in this.Controls)
              {
                  C.SuspendLayout();
                  foreach (Binding b in C.DataBindings)
                  {
                      // Help: this doesn't seem to be working.
                      b.WriteValue();
                  }
                  C.ResumeLayout();
              }
          }
          

          【讨论】:

          • 不。 =( 重点字段仍然是它们以前的值。
          【解决方案6】:

          ToolStripButton 在单击时不会获得焦点。您可以添加一些代码来(暂时)关注另一个控件。您可以聚焦标签(作为中性假人)。

          【讨论】:

          • 好的...令人惊讶的是,这很有效...我很乐意为您提供“支持”。但我发现给标签焦点是一个小技巧。除非没有人有更明智的想法,否则我不愿将其标记为“至高无上的答案”。有没有“正确”的方法来做同样的事情?
          • 例如,如果用户使用“Alt-S”来保存他们的应用程序怎么办?官方从未给出任何点击。
          猜你喜欢
          • 1970-01-01
          • 2021-05-16
          • 1970-01-01
          • 2020-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          相关资源
          最近更新 更多