QA@IT

データテーブルの削除について

2419 PV

取引先の宛名印刷プログラムを作成しています。取引先を検索し、1件毎にデータテーブル(dt1)に登録します。
登録すると、リッチテキストボックス内で改行して、行番号を付け取引先名+印刷枚数を表示させています。
1.○○会社 1枚
2.▲○会社 2枚
   ・
   ・
   ・
9.■□会社 10枚

行いたいことは以下になります。
リッチテキストボックス内で表示されている行番号の数値を、別のテキストボックス9に入力し、
ボタンを押すと、データテーブル(dt1)から、その行番号の取引先情報を削除したく思うのですが、解決に至っておりません。

以下のコード①はボタンを押すと、リッチテキストボックス内の行番号の文字列を削除する事は出来ますが、
データテーブル(dt1)から、その行番号の取引先を削除する事が出来ません。
テキストボックス9に1と入力してボタンを押せば、
リッチテキストボックス内の行番号1の取引先情報をdt1より削除したいのです。

以下は、リッチテキストボックス内から文字列を削除する事は出来ます。
① Dim st As String
st = "^" & StrConv(TextBox9.Text, VbStrConv.Wide) & "..+$[\n]*"
RichTextBox1.Text = Regex.Replace(RichTextBox1.Text, st, "", RegexOptions.Multiline)

以下のコード②は取引先コードをキーにして、dt1おり削除することは出来ます。
②Dim keyValue = "9999"
For i = dt1.Rows.Count - 1 To 0 Step -1
If dt1.Rows(i)(3).ToString() = keyValue Then →取引先コードは4列目です
dt1.Rows.Remove(dt1.Rows(i))
End If
Next
dt1.AcceptChanges()

テキストボックス9に1と入力してボタンを押せば、
リッチテキストボックス内の行番号1の取引先情報をdt1より削除したいのです。
削除されるのは1.○○会社 1枚 になります。

ご教授の程お願いいたします。

回答

※もう少し「こういう方法を考えたができなかった」とか「こうやったけど駄目だった」という質問の方がいろいろアドバイスしやすいです。

さて、いくつかやり方はあるとは思いますがひとまず一番単純な形を示します。
現状のコードを活かすとすれば取引先コードは拾えませんので行番号を手掛かりにするのが単純そうです。
(正規表現で会社名を取るという手もなくはないですが)

Dim targetRowIndex = Integer.Parse(StrConv(TextBox9.Text, VbStrConv.Narrow))
dt1.Rows.Remove( dt1.Rows(targetRowIndex -1) )
dt1.AcceptChanges()

このやり方の場合の問題は、リッチテキストボックス内のデータと DataTable内のデータが同じように並んでいないといけない事です。ですので、dt1.AcceptChanges()の後でリストボックスを表示しなおす必要が出てきます。
そしてこのやり方は単純ではあるものの、その行が本当に目的の行なのかという紐づけが弱いです。

これでも一応は実現すると思いますのが少々不安定ですので、できればRichTextBoxに行を追加する段階で取引先コードと行番号のペアを記録しておくと良くなるでしょう。
記録するにはDictionary(Of string,string) またはList(Of string) または配列などを使えばいいと思います。
そうすればTextBox9から拾った行番号を基に取引先コードが拾えるようになりますね。


回答からは外れますが、リッチテキストボックスではなくリストボックスを使うという手もありそうです。余力があれば挑戦してみてください。
登録に関しては RichTextBox1.AppendText("1.○○会社 1枚" & vbLf)
ListBox1.Items.Add("1.○○会社 1枚")になるだけです。

それとなるべくコントロールにも何のためのものかわかるような名前を付けてあげてください。

追記

とりあえず現状を解決するために以下のメソッドを用意しました(ヒントというかほぼ答えになってしまった orz )。
DataRowから削除する処理は書いてませんが、メソッドをRemoveRows(RichTextBox1.Text, Integer.Parse(TextBox9.Text))と呼べば
必要な値が変数に格納されると思います。
End Usingの後でDataTableから行を削除してみてください。

Private Sub RemoveRows(displayedText As String, targetLineNo As Integer)

    Dim removeRowIndex As Integer = 0
    Dim removeRows As Integer = 0
    Using sr = New System.IO.StringReader(displayedText)

        Dim line = sr.ReadLine()
        While line <> Nothing
            Dim sheets = Integer.Parse(Regex.Match(line, "([0-9]+)枚").Groups(1).Value)

            If line.StartsWith(StrConv(targetLineNo, VbStrConv.Wide) & ".") Then
                removeRows = sheets
                Exit While
            End If
            removeRowIndex += sheets
            line = sr.ReadLine()
        End While
    End Using

End Sub

ただ、こんな計算を後からやらなければいけないのがわかっているのであれば、
RichTextBoxを作る段階でリストなどに情報を格納しておく方が良いです。
その場合は特にキーとなる取引先コードを残すといいでしょうね。

編集 履歴 (2)
  • ありがとうございます。
    dt1.Remove(dt1.Rows(targetRowIndex - 1))の箇所で以下のエラーが発生します。

    'Remove' は 'System.Data.DataTable' のメンバーではありません。
    そこでImports System.Data.DataTableを記述しましたが、現象変わらないです。
    ご教授下さい。
    -
  • dt1.Rows.Remove(dt1.Rows(targetRowIndex - 1))の
    間違いです。Rowsが抜けてました。
    -
  • ありがとうございます。コードですと、1枚のみ削除されます。印刷枚数が1枚なら問題なしです。dt1に取引先が複数枚あった場合は、どうすればよいでしょうか?A会社のみを1枚印刷する場合は問題ありません。A会社 2枚+ B会社 4枚+C会社 6枚の場合で上記のコードですと、A会社が1枚残ります。A会社全てdt1より削除したいのです。 -
  • それはつまりリッチテキストボックスとデータテーブルですでに構造が違うということですね。であれば、RichTextBoxに行を追加する段階でなにか別の変数に記録しておくのがいいと思います。 -
  • 一応いろいろヒントは追記しておきます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。