4

[追記:]

私の望みは、新しい行を datagridview (DGV) に追加するユーザーが、その行を Access データベースに作成し、複数の行を作成してそれらの新しい行に非同期編集できるようにすることです。DGV はデータ セット テーブルで満たされています。DGV とデータベースの間にデータ セットを配置することがベスト プラクティスであることがわかりました (または、少なくとも柔軟性が得られます)。

ユーザーが作成した複数の新しい行を編集するには、データ セットがデータベースから自動インクリメント主キーを取得し、新しい行の更新されたキー値を DGV に再入力できる必要があります。または、少なくともそれが、この作業を行うことがわかった唯一の方法です。問題は、データテーブルに行を追加しようとすると、1 行ではなく 3 行になることです。


[簡潔にするために古い投稿を削除]

以下は、DGV が最初に入力され、データ セットにバインドされる方法です。

Dim ConMain As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MasterPath)
Dim ds As New DataSet

Public Sub UniversalFiller(ByVal QueryStringFill As String, ByVal DGV As DataGridView, ByVal AccessDBTableName As String)
    If IsNothing(ds.Tables(AccessDBTableName)) Then
    Else
        ds.Tables(AccessDBTableName).Clear()
    End If
    ConMain.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MasterPath
    Dim daZZ As New OleDbDataAdapter(QueryStringFill, ConMain)
    Try
        daZZ.Fill(ds, AccessDBTableName)
        DGV.DataSource = ds
        DGV.DataMember = AccessDBTableName
        DGV.AutoResizeColumns()
    Catch ex As Exception
        WriteToErrorLog(ex.Message, ex.StackTrace, ex.GetHashCode, ex.Source, ex.ToString)
        ds.Clear
        MsgBox("There was an error filling the DGV, ds.cleared") 'this is for my notes, not user error'
    End Try

End Sub

アップデート:

私はまだこの問題を理解できません。これは、処理時に呼び出されDGV.UserAddedRowます。 元のコードは 1 行を追加するだけの最善の方法ではなかった可能性があることを知りましたが、新しい行を作成しても同じ問題が発生します。

Dim daZZ As New OleDbDataAdapter(DBSelectQuery, ConMain)
Dim CurrentCellPoint As Point = DGV.CurrentCellAddress
Dim CurrentCellText As String = DGV.CurrentCell.Value.ToString
Dim cmdBldr As New OleDbCommandBuilder(daZZ)
cmdBldr.QuotePrefix = "["
cmdBldr.QuoteSuffix = "]"
MsgBox("1")
Dim DaZZDataRow As DataRow = ds.Tables(DTName).NewRow
MsgBox("2")
DaZZDataRow(CurrentCellPoint.X) = CurrentCellText
MsgBox("3")
ds.Tables(DTName).Rows.Add(DaZZDataRow)
MsgBox("4")
daZZ.InsertCommand = cmdBldr.GetInsertCommand()
MsgBox("5")
daZZ.Update(ds.Tables(DTName))
MsgBox("6")
ds.Tables(DTName).Clear()
daZZ.Fill(ds, DTName)
MsgBox("5")
daZZ.Update(ds.Tables(DTName))
DGV.CurrentCell = DGV(CurrentCellPoint.X, CurrentCellPoint.Y)

問題は常にds.Tables(DTName).Rows.Add()ステップです。の括弧内は何を入れても構いません.Add()。数値または 0 を含む任意の整数にすることができ、3 行になります。複数回呼び出されることはありません。を呼び出すだけds.Tables(DTName).Rows.Add()です。

それが 1 行の空白行を追加する正しい方法でない場合、それは何ですか? SQLの挿入/更新コマンドを投稿できますが、追加は1行ではなく3行になるため、それは問題ではありません。明確にするために、MsgBox項目を1回だけ実行して3行を生成します。

また、興味深いことに、InsertAt コマンドでも同じ結果が得られます。

ds.Tables(DTName).Rows.InsertAt(DaZZDataRow, CurrentCellPoint.Y) 代わりに、ds.Tables(DTName).Rows.Add()まだ 3 つの新しい行が生成されます。Access の新しいスクラッチ DB でもこれを試してみましたが、同じ問題が発生しました。

これは、VS2012 プロジェクトとダミー データベースとしてのコードの実例です。これは非常に必要最小限のものです。つまり、エラー処理はありませんが、エラーを表示し、利便性を高めるために行を削除することもできます。見てくれた人ありがとう。

4

2 に答える 2

1

この質問に対して基本に立ち返って、新しいレコードを追加するときに生成された AutoNumber ID 値を DataGridView に表示させるという問題に集中しました。まず、フォームに DataGridView コントロールを追加し、[プロジェクト データ ソースの追加...] ウィザードを使用して、Access データベース "Database1.accdb" の [Chemicals] という名前のテーブルに接続します。(質問のサンプル コードの以前のバージョンは [Chemicals] という名前のテーブルを参照していたので、それを使用しました。)

私が終わったとき、私は自分のプロジェクトに次の「もの」を持っていました:

  • BindingSource にバインドされたフォームの DataGridView コントロール ( dataGridView1) (以下を参照)

  • database1DataSetAccess データベースに関連付けられた DataSet ( )

  • chemicalsBindingSourceの [Chemicals] テーブルに関連付けられた BindingSource ( ) は、私の DataGridViewdatabase1DataSetの として機能しますDataSource

  • chemicalsTableAdapterDataSet と実際のデータベース間のデータ フローを管理するTableAdapter ( )。

Form1_Loadウィザードは、私のメソッドで次のコード行も提供してくれました。(私は C# を使用しましたが、VB.NET も非常に似ています。)

// TODO: This line of code loads data into the 'database1DataSet.Chemicals' table. You can move, or remove it, as needed.
this.chemicalsTableAdapter.Fill(this.database1DataSet.Chemicals);

アプリケーションを実行し、DataGridView で既存のレコードを表示するために必要なのはこれだけでした。

ここで、DataGridView の更新をデータベースにプッシュして戻し、新しく作成されたレコードの AutoNumber 値を取得するために、RowLeaveイベントを使用しました。UserAddedRowイベントが発生するのが早すぎる (ユーザーが新しい行に入力を開始した直後) ことがわかり、ユーザーが行の編集を完了するまで待ってから、何かを実行したかったのです。

私が使用したコードは次のとおりです(これもC#です)

private void Form1_Load(object sender, EventArgs e)
{
    fillErUp();
}

private void fillErUp()
{
    // (moved from Form1_Load to its own method so it could also be called from _RowLeave, below)
    // TODO: This line of code loads data into the 'database1DataSet.Chemicals' table. You can move, or remove it, as needed.
    this.chemicalsTableAdapter.Fill(this.database1DataSet.Chemicals);
}

private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    if (dgv.IsCurrentRowDirty)
    {
        Cursor.Current = Cursors.WaitCursor;
        dgv.EndEdit();  // flush changes from DataGridView to BindingSource
        chemicalsBindingSource.EndEdit();  // flush changes from BindingSource to DataSet
        this.chemicalsTableAdapter.Update(this.database1DataSet);  // update database
        int currentRow = e.RowIndex;
        if (Convert.ToInt32(dgv.Rows[currentRow].Cells[0].Value) < 0)
        {
            // negative AutoNumber value indicates that the row has just been added
            int currentCol = e.ColumnIndex;
            fillErUp();  // re-fill the table in the DataSet, and hence the DataGridView as well
            dgv.CurrentCell = dataGridView1[currentCol, currentRow];
        }
        Cursor.Current = Cursors.Default;
    }
}

これは確かに完全な製品コードではありませんが、役に立てば幸いです。

re: コメントを編集

Visual Studio の "魔法使い" に頼らずに同じ結果を達成できるかどうかを確認するために、以前のソリューションをもう一度試してみました。今回の私のアプローチは次のとおりです。

  • 新しい C# Windows Forms プロジェクトを開きました。

  • DataSetオブジェクト、BindingSourceオブジェクト、およびDataGridViewオブジェクトを空白のフォームにドラッグ アンド ドロップしました。dataSet1それぞれ、bindingSource1、 と名付けられましdataGridView1た。

  • イベント ハンドラーを作成Form1_Loadし、dataGridView1_RowLeave次のような独自のコードを追加しました。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace dgvTest2
{
    public partial class Form1 : Form
    {
        OleDbConnection con = new OleDbConnection();
        OleDbDataAdapter da = new OleDbDataAdapter();
        OleDbCommandBuilder cb;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            con.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Public\Database1.accdb";
            con.Open();
            da.SelectCommand = new OleDbCommand("SELECT * FROM Chemicals", con);
            cb = new OleDbCommandBuilder(da);
            cb.QuotePrefix = "["; cb.QuoteSuffix = "]";
            this.dataSet1.Tables.Add(new DataTable("Chemicals"));
            this.bindingSource1.DataSource = this.dataSet1;
            this.bindingSource1.DataMember = "Chemicals";
            this.dataGridView1.DataSource = this.bindingSource1;
            fillErUp();
        }

        private void fillErUp()
        {
            this.dataSet1.Tables["Chemicals"].Clear();
            da.Fill(this.dataSet1.Tables["Chemicals"]);
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;
            if (dgv.IsCurrentRowDirty)
            {
                Cursor.Current = Cursors.WaitCursor;
                dgv.EndEdit();  // flush changes from DataGridView to BindingSource
                bindingSource1.EndEdit();  // flush changes from BindingSource to DataSet
                da.Update(this.dataSet1.Tables["Chemicals"]);  // update database
                int currentRow = e.RowIndex;
                if (dgv.Rows[currentRow].Cells[0].Value == DBNull.Value)
                {
                    // a null ID value indicates that the row has just been added
                    int currentCol = e.ColumnIndex;
                    fillErUp();  // re-fill the table in the DataSet, and hence the DataGridView as well
                    dgv.CurrentCell = dataGridView1[currentCol, currentRow];
                }
                Cursor.Current = Cursors.Default;
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            con.Close();
        }
    }
}
于 2014-01-16T20:05:20.577 に答える
1

これは、あなたの取引のいくつかの部分に対する私の改訂版です。

    daZZ.InsertCommand = cmdBldr.GetInsertCommand()

私はまだ InsertCommand が必要だとは思わない。これはあなたの3行のうちの1つを作成していると思います。

    ds.Tables(DTName).Rows.Add(DaZZDataRow)

これで 2 番目の行が作成されます。これは有効ですが、どちらも必要ありません。

3 番目の行は、DataBinding のために DataGridView によって作成されています。テーブルを DataGridView にバインドし、DGV が "AddRows" を許可されている場合、挿入された行も生成されます。

これらの 2 つの項目とクリア ラインを完全に削除してみてください (必要ないと思います)。DGV に現在追加されている行が 1 行追加されるはずです。

UPDATE と FILL を呼び出して、グリッド内のデータを再同期する必要があります。

于 2014-01-16T17:06:03.640 に答える