【问题标题】:Checkboxes are keeping myCurrencyManager.AddNew() from working properly复选框使 myCurrencyManager.AddNew() 无法正常工作
【发布时间】:2020-07-31 14:14:37
【问题描述】:

我有一个功能齐全的 Windows 窗体应用程序,它使用绑定到 Access DB 的只读数据网格视图开发。
数据绑定文本框用于编辑字段。然后我在数据库、datagridview 和表单中添加了 3 个复选框字段。然后像文本框一样添加chkName.DataBindings.Add("Checked", DBTable,"Field")。复选框正常工作,显示正确的数据。

仅当我尝试使用 myCurrencyManager.AddNew() 添加一行时,它才不起作用。除了在 datagridview 的末尾添加一个不可访问的行之外,它什么也不做。当我注释掉 Checkbox DataBindings 行时,一切正常(没有功能复选框)。

有什么想法吗?

代码如下:

Public Class frmRoutes
    Dim RoutesConnection As OleDbConnection
    Dim JS1Adapter As New OleDbDataAdapter
    Dim JS1Table As New DataTable("JOBSITES")
    Dim JSBS As BindingSource
    Dim JS1State As String = "Edit"

    Private Sub frmRoutes_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        RoutesConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source = C:\Microsoft\JS1TestDB.mdb")
        RoutesConnection.Open()
        Dim JobSitesCommand = New OleDbCommand _
        ("SELECT REF, STREET, CITY, SPEC, HELPER " +
        "FROM Jobsites ORDER BY REF", RoutesConnection)

        JS1Adapter.SelectCommand = JobSitesCommand
        JS1Adapter.Fill(JS1Table)

        JSBS = New BindingSource()
        JSBS.DataSource = JS1Table
        grdJobSites.DataSource = JSBS

        txtRef.DataBindings.Add("Text", JSBS, "REF")
        txtStreet.DataBindings.Add("Text", JSBS, "STREET")
        txtCity.DataBindings.Add("Text", JSBS, "CITY")
        'chkSpecial.DataBindings.Add("Checked", JSBS, "SPEC")  'THESE 2 CHECKBOX DATABINDINGS CAUSE THE 'ADDNEW' METHOD TO FAIL
        'chkHelper.DataBindings.Add("Checked", JSBS, "HELPER")
    End Sub

    Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
        Try
            JSBS.AddNew()
        Catch ex As Exception
            MessageBox.Show("Error Adding a New row.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
        JS1State = "Add"
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        JSBS.CancelEdit()
        JS1State = "View"
    End Sub
End Class

【问题讨论】:

  • 数据库中添加的“CheckBox”字段的默认值是多少?您确定添加新行时没有任何异常吗?
  • 不要直接使用CurrencyManager。在设计器中将BindingSource 添加到您的表单,将DataTable 绑定到BindingSource 并将其绑定到您的控件。 BindingSource 完成所有 CurrencyManager 所做的工作,甚至更多。
  • 与此类问题的情况一样,您应该创建一个简单的测试项目并隔离导致问题的特定功能。您不需要数据库来填充 DataTable,这是您的控件实际绑定的对象,而不是 Access 数据库。然后,您可以尝试找出测试项目中的哪些更改会产生预期行为和异常行为。如果还是不能解决问题,至少可以给我们发minimal, reproducible example
  • 回复@jmcilhinney - 我已经创建了我的应用程序的最小版本,现在也使用 BindingSource 而不是货币管理器,但结果相同 - 如果我绑定了复选框,AddNew 方法不会好好工作。我正在使用 Visual Studio 进行开发。我可以复制和粘贴代码,但是 Access DB 文件呢?让我知道如何进行。再次感谢。
  • 该数据文件无关紧要。您的应用程序正在使用DataTable。这就是绑定到您的BindingSource 的内容。您可以编写代码以任何您想要的特定方式填充DataTable,这意味着您可以使用与数据库中完全相同的数据或任何其他数据进行测试。我的第一个想法是您的数据库中有可为空的数据,但您的 CheckBoxes 仅代表两种状态。这有点猜测,但这是我首先要看的地方。此外,MRE 的想法是我们可以重现您的问题,但您没有向我们提供示例。记住 MINIMAL。

标签: vb.net checkbox datagridview


【解决方案1】:

问题正如我已经说过的:可空数据。我刚刚测试了这段代码(一个实际的最小示例):

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim table As New DataTable

        With table.Columns
            .Add("Name", GetType(String))
            .Add("Flag", GetType(Boolean))
        End With

        With table.Rows
            .Add("Peter", True)
            .Add("Paul", False)
            .Add("Mary", True)
        End With

        BindingSource1.DataSource = table
        TextBox1.DataBindings.Add("Text", BindingSource1, "Name")
        CheckBox1.DataBindings.Add("Checked", BindingSource1, "Flag")
    End Sub

End Class

并且在添加新行(通过BindingNavigator)时发生无效转换异常,因为Flag 列默认包含DBNull.Value,并且不能转换为Boolean 类型,这是@ 所必需的987654326@ 财产。有两种可能的解决方案。最好的方法取决于您是否希望能够保存空值。

  1. 如果您不想保存空值,请为该列指定默认的Boolean 值。那可能是False,但如果你愿意,也可能是True。这样,当添加新行时,该列已经包含与Checked 属性兼容的Boolean 值。在我的例子中,这个:
.Add("Flag", GetType(Boolean))

变成这样:

.Add("Flag", GetType(Boolean)).DefaultValue = False

在您的情况下,您必须在填充并设置该属性后从 DataTable 获取相应的列。

  1. CheckBoxThreeState 属性设置为True,绑定到CheckState 属性而不是Checked 属性,并在数据源中可为空的Boolean 数据和@ 987654341@ 控件中的值。对我的示例进行更改可能如下所示:
Public Class Form1

    Private WithEvents checkStateBinding As Binding

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim table As New DataTable

        With table.Columns
            .Add("Name", GetType(String))
            .Add("Flag", GetType(Boolean))
        End With

        With table.Rows
            .Add("Peter", True)
            .Add("Paul", False)
            .Add("Mary", True)
        End With

        BindingSource1.DataSource = table
        TextBox1.DataBindings.Add("Text", BindingSource1, "Name")

        checkStateBinding = New Binding("CheckState", BindingSource1, "Flag")

        CheckBox1.DataBindings.Add(checkStateBinding)
    End Sub

    Private Sub CheckStateBinding_Format(sender As Object, e As ConvertEventArgs) Handles checkStateBinding.Format
        'Convert from nullable Boolean to CheckState.
        If TryCast(e.Value, DBNull) Is DBNull.Value Then
            e.Value = CheckState.Indeterminate
        ElseIf CBool(e.Value) Then
            e.Value = CheckState.Checked
        Else
            e.Value = CheckState.Unchecked
        End If
    End Sub

    Private Sub CheckStateBinding_Parse(sender As Object, e As ConvertEventArgs) Handles checkStateBinding.Parse
        'Convert from CheckState to nullable Boolean.
        Select Case DirectCast(e.Value, CheckState)
            Case CheckState.Indeterminate
                e.Value = DBNull.Value
            Case CheckState.Checked
                e.Value = True
            Case CheckState.Unchecked
                e.Value = False
        End Select
    End Sub

End Class

Binding 需要从控件的数据源获取数据时引发其Format 事件,当它需要从数据源的控件获取数据时引发其Parse 事件。如果两者之间的类型和/或值不匹配,您可以自己进行翻译。

【讨论】:

    猜你喜欢
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多