連載:Windowsフォーム開発入門【Visual Studio 2010対応】

リモート・データ活用術〜SQL Server編〜

初音 玲
2011/02/09

編集画面(ダイアログ画面)を作成

 ダイアログ・ボックスとなる編集画面は、「Windows フォーム」テンプレートから独自に作成する。具体的なUIデザインは図15のとおりである。

図15 編集画面(ダイアログ画面)のUIデザイン

ShowDialogメソッドを拡張する

 編集画面は、拡張したShowDialogメソッドでのみ呼び出せる(通常のShowDiaplogメソッドでは呼び出せないようにしている)。この拡張ShowDiaplogメソッドの第3パラメータに、(Pubsデータベースの)titlesテーブルPK(PrimaryKey:主キー)であるtitle_idフィールドの値を指定して呼び出すと、PKに一致するtitlesテーブルの1レコードの内容を各コントロールに表示して、それらの値を編集する機能を、この編集画面に実装している。

 拡張ShowDiaplogメソッドの実装コードは下記のとおりだ。

Private EditUserID As String = Nothing
Private EditPassword As String = Nothing
Private EditTitleID As String = Nothing
Private EditDs As DataSet = Nothing
Private IsUpdate As Boolean = False

Public Overloads Function ShowDialog(ByVal owner As IWin32Window,
                                     ByVal userID As String,
                                     ByVal password As String,
                                     ByVal titleID As String) _
                                 As DialogResult
  Me.EditUserID = userID
  Me.EditPassword = password
  Me.EditTitleID = titleID
  Return MyBase.ShowDialog(owner)
End Function
private String EditUserID = null;
private String EditPassword = null;
private String EditTitleID = null;
private DataSet EditDs = null;
private Boolean IsUpdate = false;

public DialogResult ShowDialog(IWin32Window owner,
                               String userID,
                               String password,
                               String titleID)
{
  this.EditUserID = userID;
  this.EditPassword = password;
  this.EditTitleID = titleID;
  return base.ShowDialog(owner);
}
リスト7 ShowDiaplogメソッドを拡張したコード例(上:VB、下:C#)

 編集画面では、ShowDialogメソッドで指定された「ID」「パスワード」「タイトルID」をフォーム・クラス内のPrivate変数に保持して、それをShownイベント・プロシージャ内で利用している。

 拡張したShowDialogメソッドの中でSQL Serverに接続してデータを取得するように実装した場合、ダイアログが表示される前に実行されるため、タイトル一覧画面の右クリック・メニューの[編集]をクリックしてから、編集画面が表示されるまでに、(データ取得の時間がかかって)間が空いてしまう。これを回避するために、Shownイベント・プロシージャにこの処理を実装している。

SQL Serverからデータを取得する

 編集画面でも、(タイトル一覧画面と)同様にデータ・アクセス部分をWindowsフォームから分離したので、SQL Serverから1レコード分のデータを取得するメソッド(=サンプルではGetTitleDsItemメソッド)もDataAccessClassクラスに記述する。具体的には下記のメソッドを記述する。

Friend Function GetTitleDsItem(ByVal userID As String,
                               ByVal password As String,
                               ByVal titleID As String) As DataSet
  Dim ds As New DataSet
  Using _cn As New SqlConnection
    _cn.ConnectionString = String.Format(My.Settings.ConnectonString,
                                         userID,
                                         password)
    _cn.Open()
    Using _cmd As New SqlCommand
      _cmd.Connection = _cn
      _cmd.CommandText = "SELECT * " &
                         "FROM titles " &
                         "WHERE title_id=@TitleID"
      _cmd.Parameters.Add(New SqlClient.SqlParameter("TitleID", titleID))
      Using _da As New SqlDataAdapter
        _da.SelectCommand = _cmd
        _da.Fill(ds, "EditTitle")
        ds.Tables("EditTitle").PrimaryKey = New DataColumn() {ds.Tables("EditTitle").Columns("title_id")}
      End Using
    End Using
  End Using
  Return ds
End Function
internal DataSet GetTitleDsItem(String userID, String password, String titleID)
{
  DataSet ds = new DataSet();
  using (SqlConnection _cn = new SqlConnection())
  {
    _cn.ConnectionString =
      String.Format(WinFormSQLCs.Properties.Settings.Default.ConnectonString,
      userID,
      password);
    _cn.Open();
    using (SqlCommand _cmd = new SqlCommand())
    {
      _cmd.Connection = _cn;
      _cmd.CommandText = @"SELECT * " +
                          "FROM titles " +
                          "WHERE title_id=@TitleID";
      _cmd.Parameters.Add(new SqlParameter(@"TitleID", titleID));
      using (SqlDataAdapter _da = new SqlDataAdapter())
      {
        _da.SelectCommand = _cmd;
        _da.Fill(ds, "EditTitle");
        ds.Tables["EditTitle"].PrimaryKey = new DataColumn[] { ds.Tables["EditTitle"].Columns["title_id"] };
      }
    }
  }
  return ds;
}
リスト8 SQL Serverから1レコード・データを取得するコード例(上:VB、下:C#)

 前述のタイトル一覧取得時のSELECT文では、titleフィールドの内容に対してLIKE演算子を使ったWHERE句で(titlesテーブル内の一致する全件のデータを)検索していた。編集画面の1レコードだけ取得するSELECT文では、「PKであるtitle_idフィールドが特定の値に一致するか」をWHERE句に指定して(titlesテーブル内の一致する1件のデータを)検索している。そのほかの部分はタイトル一覧取得のときのコードと同じだ。

 このようにADO.NETでは、SELECT文の記述を書き換えるだけで、取得するデータを変えることができる。

編集画面表示時に自動的にデータを表示する

 1レコードのデータを編集画面に表示するにはいろいろな手法が考えられるが、このサンプルではBindingSourceコントロールを使って画面に配置したコントロールとレコードをデータ連結している。下記のコードでは、Shownイベント・プロシージャ内にその処理を実装している。

Private Sub Me_Shown(sender As Object, e As System.EventArgs) _
         Handles Me.Shown
  Me.Text = String.Format(Me.Tag.ToString, EditTitleID)
  Me.Cursor = Cursors.WaitCursor
  Try
    Using _proc As New DataAccessClass
      Me.EditDs = _proc.GetTitleDsItem(Me.EditUserID,
                                       Me.EditPassword,
                                       Me.EditTitleID)
      Me.Edit_BindingSource.DataSource = Me.EditDs.Tables("EditTitle")
      Me.TitleId_TextBox.DataBindings.Add(New Binding("Text",
                                          Me.Edit_BindingSource,
                                          "title_id",
                                          True,
                                          DataSourceUpdateMode.OnValidation,
                                          String.Empty))
                
                
               (中略)
                
                
      Me.Notes_TextBox.DataBindings.Add(New Binding("Text",
                                        Me.Edit_BindingSource,
                                        "notes",
                                        True,
                                        DataSourceUpdateMode.OnValidation,
                                        String.Empty))
      Me.Pubdate_DateTimePicker.DataBindings.Add(New Binding("Value",
                                                 Me.Edit_BindingSource,
                                                 "pubdate",
                                                 True,
                                                 DataSourceUpdateMode.OnValidation,
                                                 DateTime.Now.Date))
      If Me.EditDs.Tables("EditTitle").Rows.Count > 0 Then
        Me.OK_Button.Enabled = True
      Else
        Me.OK_Button.Enabled = False
      End If
      IsUpdate = False
    End Using
  Catch ex As Exception
    MessageBox.Show(ex.Message, Me.Text)
  Finally
    Me.Cursor = Cursors.Default
  End Try
End Sub
private void Me_Shown(object sender, EventArgs e)
{
  this.Text = String.Format((string)this.Tag, EditTitleID);
  this.Cursor = Cursors.WaitCursor;
  try
  {
    using (DataAccessClass _proc = new DataAccessClass())
    {
      this.EditDs = _proc.GetTitleDsItem(this.EditUserID,
                                         this.EditPassword,
                                         this.EditTitleID);
      this.Edit_BindingSource.DataSource = this.EditDs.Tables["EditTitle"];
      this.TitleId_TextBox.DataBindings.Add(new Binding("Text",
                                            this.Edit_BindingSource,
                                            "title_id",
                                            true,
                                            DataSourceUpdateMode.OnValidation,
                                            String.Empty));
        
        
       (中略)
        
        
      this.Notes_TextBox.DataBindings.Add(new Binding("Text",
                                          this.Edit_BindingSource,
                                          "notes",
                                          true,
                                          DataSourceUpdateMode.OnValidation,
                                          String.Empty));
      this.Pubdate_DateTimePicker.DataBindings.Add(new Binding("Value",
                                                   this.Edit_BindingSource,
                                                   "pubdate",
                                                   true,
                                                   DataSourceUpdateMode.OnValidation,
                                                   String.Empty));
      if (this.EditDs.Tables["EditTitle"].Rows.Count > 0)
      {
        this.OK_Button.Enabled = true;
      }
      else
      {
        this.OK_Button.Enabled = false;
      }
      IsUpdate = false;
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, this.Text);
  }
  finally
  {
    this.Cursor = Cursors.Default;
  }
}
リスト9 編集画面表示直後にデータを表示するコード例(上:VB、下:C#)

編集画面の内容を保存する

 BindingSourceコントロールを使ったWindowsフォームで、さらにデータ・アクセス部分を別のクラス・ファイルに分離した場合、編集画面の内容を保存するコードは(下記のとおり)極めてシンプルになる。

Private Sub OK_Button_Click(sender As System.Object,
                            e As System.EventArgs) _
            Handles OK_Button.Click
  IsUpdate = Not IsDataUpdate()
  Me.DialogResult = DialogResult.OK
End Sub

Private Function IsDataUpdate() As Boolean
  Dim isOK As Boolean = False

  Try
    Me.Edit_BindingSource.EndEdit()
    Using _proc As New DataAccessClass
      isOK = _proc.SetTitleDsItem(Me.EditUserID,
                                  Me.EditPassword,
                                  Me.EditTitleID,
                                  Me.EditDs)
    End Using
    isOK = True
  Catch ex As Exception
    MessageBox.Show(ex.Message, Me.Text)
  End Try
  Return isOK
End Function
private void OK_Button_Click(object sender, EventArgs e)
{
  this.IsUpdate = !IsDataUpdate();
  this.DialogResult = DialogResult.OK;
}

private Boolean IsDataUpdate()
{
  Boolean isOK = false;

  try
  {
    this.Edit_BindingSource.EndEdit();
    using (DataAccessClass _proc = new DataAccessClass())
    {
      isOK = _proc.SetTitleDsItem(this.EditUserID,
                                  this.EditPassword,
                                  this.EditTitleID,
                                  this.EditDs);
    }
    isOK = true;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message, this.Text);
  }
  return isOK;
}
リスト10 編集画面の内容を保存するコード例(上:VB、下:C#)

 BindingSourceコントロールを使用しているので、そのEndEditメソッド(=上記のコードでは「Edit_BindingSource.EndEditメソッド」)を実行するだけで、BindingSourceコントロールを経由して、編集画面の内容をデータセットに反映できる。DataAccessClassクラスのSetTitleDsItemメソッドにより、そのデータセットの内容をSQL Serverに保存している。

SQL Serverにデータを保存する

 呼び出されたSetTitleDsItemメソッド内では、データアダプタ(=下記のコードでは「SqlDataAdapter」)のUpdateメソッドにより、データセットの内容をSQL Serverに保存している。

 Updateメソッドを実行するには、UPDATE文、INSERT文、DELETE文のSQL文をデータアダプタにあらかじめ設定しておかなければならない。これらのSQL文をすべて手動でコーディングしてもいいが、ADO.NETではSELECT文からUPDATE文、INSERT文、DELETE文を生成してくれるコマンド・ビルダ(=下記のコードでは「SqlCommandBuilder」)が提供されている。

 以上の内容を実装したのが下記のコードだ。

Friend Function SetTitleDsItem(userID As String,
                               password As String,
                               titleID As String,
                               ds As DataSet) As Boolean
  Dim isOK As Boolean = False

  Using _cn As New SqlConnection
    _cn.ConnectionString = String.Format(My.Settings.ConnectonString,
                                         userID,
                                         password)
    _cn.Open()
    Using _tr As SqlTransaction = _cn.BeginTransaction
      Try
        Using _cmd As New SqlCommand
          _cmd.Connection = _cn
          _cmd.Transaction = _tr
          _cmd.CommandText = "SELECT * " &
                     "FROM titles " &
                    "WHERE title_id=@TitleID"
          _cmd.Parameters.Add(New SqlParameter("TitleID", titleID))
          Using _da As New SqlDataAdapter
            _da.SelectCommand = _cmd
            Using _cb As New SqlCommandBuilder(_da)
              _cb.ConflictOption = ConflictOption.OverwriteChanges
              _cb.GetInsertCommand(True).Connection = _cn
              _cb.GetInsertCommand(True).Transaction = _tr
              _cb.GetUpdateCommand(True).Connection = _cn
              _cb.GetUpdateCommand(True).Transaction = _tr
              _cb.GetDeleteCommand(True).Connection = _cn
              _cb.GetDeleteCommand(True).Transaction = _tr
              _da.Update(ds, "EditTitle")
            End Using
            _tr.Commit()
          End Using
          isOK = True
        End Using
      Catch ex As Exception
        _tr.Rollback()
        Throw ex
      End Try
    End Using
  End Using
  Return isOK
End Function
internal Boolean SetTitleDsItem(String userID, String password, String titleID, DataSet ds)
{
  Boolean isOK = false;
  using (SqlConnection _cn = new SqlConnection())
  {
    _cn.ConnectionString =
      String.Format(WinFormSQLCs.Properties.Settings.Default.ConnectonString,
                    userID,
                    password);
    _cn.Open();
    using (SqlTransaction _tr = _cn.BeginTransaction())
    {
      try
      {
        using (SqlCommand _cmd = new SqlCommand())
        {
          _cmd.Connection = _cn;
          _cmd.Transaction = _tr;
          _cmd.CommandText = @"SELECT * " +
                              "FROM titles " +
                              "WHERE title_id=@TitleID";
          _cmd.Parameters.Add(new SqlParameter(@"TitleID", titleID));
          using (SqlDataAdapter _da = new SqlDataAdapter())
          {
            _da.SelectCommand = _cmd;
            using (SqlCommandBuilder _cb = new SqlCommandBuilder(_da))
            {
              _cb.ConflictOption = ConflictOption.OverwriteChanges;
              _cb.GetInsertCommand(true).Connection = _cn;
              _cb.GetInsertCommand(true).Transaction = _tr;
              _cb.GetUpdateCommand(true).Connection = _cn;
              _cb.GetUpdateCommand(true).Transaction = _tr;
              _cb.GetDeleteCommand(true).Connection = _cn;
              _cb.GetDeleteCommand(true).Transaction = _tr;
              _da.Update(ds, "EditTitle");
            }
            _tr.Commit();
          }
          isOK = true;
        }
      }
      catch (Exception ex)
      {
        _tr.Rollback();
        throw ex;
      }
    }
  }
  return isOK;
}
リスト11 SQL Serverにデータを保存するコード例(上:VB、下:C#)

 最後に、ここまでに作成してきたアプリケーションを完成させよう。


 INDEX
  [連載]Windowsフォーム開発入門【Visual Studio 2010対応】
  リモート・データ活用術〜SQL Server編〜
    1.SQL Server Expressの設定
    2.画面遷移/スプラッシュ・スクリーン/ログイン画面
    3.タイトル一覧画面(メイン画面)
  4.編集画面(ダイアログ画面)
    5.最終仕上げ

インデックス・ページヘ  「Windowsフォーム開発入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH