- 題名: BindingListの要素内の値が変更されたらイベントを発生させたい
- 日時: 2013/05/27 12:02:39
- ID: 31589
- この記事の返信元:
- (なし)
- この記事への返信:
- [31591] Re[1]: BindingListの要素内の値が変更されたらイベントを発生させたい2013/05/27 19:43:53
- ツリーを表示
■No31589に返信(やむさんの記事)
> listItem.differenceの値を計算して設定させたいのです。
であれば、
'回収残
Public Property difference As Integer = 0
とするのではなく
'回収残
Public ReadOnly Property difference As Integer
Get
Return bill - (deposit + commission)
End Get
End Property
としておいた方が手っ取り早いかと。
> どちらにも対応させる方法はないでしょうか。
そもそも、DataTable/DataSet のまま管理しては駄目なのでしょうか?
DataTable そのものを DataGridView にバインドしていれば、
元の DataTable を編集することで、DataGridView の表示は変わりますし、
difference 列の件についても、「式列」を用意するだけで済むはずです。
Public Class Form1
Private WithEvents DataGridView1 As DataGridView
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DataGridView1 = New DataGridView()
DataGridView1.Dock = DockStyle.Fill
Me.Controls.Add(DataGridView1)
DataGridView1.DataSource = CreateSampleTable()
End Sub
Private Function CreateSampleTable() As DataTable
Dim tbl As New DataTable()
'実際はデータベースから取得
tbl.Columns.Add("code")
tbl.Columns.Add("name")
tbl.Columns.Add("bill", GetType(Decimal))
tbl.Columns.Add("deposit", GetType(Decimal))
tbl.Columns.Add("commission", GetType(Decimal))
tbl.PrimaryKey = {tbl.Columns("code")}
'サンプルデータ
Dim r As New Random()
For n As Integer = 10 To 50
tbl.Rows.Add(CStr(n * 10 + 1), StrDup(n \ 2, "*"), r.Next(6, 10), r.Next(3, 5), r.Next(0, 3))
Next
'本題の「difference」列を作成
tbl.Columns.Add("difference", GetType(Decimal), "bill - (deposit + commission)")
Return tbl
End Function
End Class
もしも BindingList で管理した方が都合が良いのあれば、
「変更通知」の機能を実装する必要があります。
http://msdn.microsoft.com/ja-jp/library/xz45s2bh.aspx
具体的には、listItem クラスに INotifyPropertyChanged を
Implements した上で、それぞれのプロパティを自動実装プロパティから
カスタム実装にして、値が変更されたときに INotifyPropertyChanged の
PropertyChanged イベントを発行するようにします。
'請求額
Private _bill As Integer = 0
Public Property bill() As Integer
Get
Return _bill
End Get
Set(ByVal value As Integer)
_bill = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("bill"))
End Set
End Property
魔界の仮面弁士様
ありがとうございます。
> そもそも、DataTable/DataSet のまま管理しては駄目なのでしょうか?
ダメというわけではないのですが、個人的な好みの問題で
わざわざDataSourceに指定するクラスを作成して管理しています。
> もしも BindingList で管理した方が都合が良いのあれば、
> 「変更通知」の機能を実装する必要があります。
> http://msdn.microsoft.com/ja-jp/library/xz45s2bh.aspx
教えていただいた方法で、listItemクラスを変更し、frm側でイベントを拾う
方法を試してみました。
ところが、最初のsetData()時には問題なくイベントを拾ってくれるのですが、
DataGridViewに直接入力した場合にはイベントを拾いません。
何がおかしいのか、アドバイス頂けると幸いです。
宜しくお願いします。
-- 以下ソース 変更したlistItemクラスと、frmクラスの追加部分のみ抜出
Public Class frm
Private WithEvents item As listItem '追加
'追加 DataGridViewに直接値を入力した際にここを通らない
Private Sub item_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Handles item.PropertyChanged
Dim line As listItem = DirectCast(sender, listItem)
line.difference = line.bill - (line.deposit + line.commission)
End Sub
End Class
Public Class listItem
Implements INotifyPropertyChanged
Dim _bill As Integer = 0
Dim _deposit As Integer = 0
Dim _commission As Integer = 0
Public Property code As String = ""
Public Property name As String = ""
Public Property bill As Integer
Get
Return _bill
End Get
Set(value As Integer)
If Not value = _bill Then
_bill = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("bill"))
End If
End Set
End Property
Public Property deposit As Integer
Get
Return _deposit
End Get
Set(value As Integer)
If Not value = _deposit Then
_deposit = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("deposit"))
End If
End Set
End Property
Public Property commission As Integer
Get
Return _commission
End Get
Set(value As Integer)
If Not value = _commission Then
_commission = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("commission"))
End If
End Set
End Property
Public Property difference As Integer = 0
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
自己解決です。
setData()内でitem を new した際、イベントの紐づけを行うのが抜けていました。
大変お騒がせしました。
アドバイス頂いた魔界の仮面弁士様、ありがとうございました 。
これにて解決としたいと思います。
Private Sub setData()
'データ取得処理
For Each rec As DataRow In dt.Rows
'↓この部分を変更
item = New listItem
AddHandler item.PropertyChanged, AddressOf item_PropertyChanged
'↑この部分を変更
’以降データ格納処理
Next
End Sub
分類:[.NET]
お世話になります。 表題の件、 BindingListをDataGeidViewのDataSourceに指定し、一覧を表示させています。 データ検索時にBindingListの要素(listItem.deposit または listItem.commission) の値が変更されたらイベントを発生させ、listItem.differenceの値を計算して設定 させたいのです。 listItem.commission をDataGridView上で入力させた際にも同様な処理を行いたい場合、 DataGridView_CellValueChanged で処理できますが、その場合だとsetData()時に処理ができません。 どちらにも対応させる方法はないでしょうか。 お知恵をお貸しください。 宜しくお願いします。 --以下ソース-- Public class frm Private dataList As BindingList(Of listItem) Public sub frm_Load(sender as Object, e as EventArgs) dataList = New BindingList(Of listItem) dgvList.AutoGenerateColumns = False dgvList.DataSource = dataList setColumns() setData() End Sub Private Sub setColumns() setTextColumn("code", "コード") setTextColumn("name", "名前") setTextColumn("bill", "請求額") setTextColumn("deposit", "入金額") setTextColumn("commission", "手数料") setTextColumn("difference", "回収残") End Sub Private Sub setTextColumn(name As String, head as String) Dim col As New DataGridViewTextBoxColumn col.Name = name col.DataPropertyName = name col.HeaderText = head dgvList.Columns.Add(col) End Sub Private Sub setData() Dim common As New clsCommon Dim sql As String = "データ検索用SQL" Dim db As New clsDB 'SQLを実行し、結果をDataTableに格納 Dim dt As DataTable = db.getData(sql) For Each rec As DataRow In dt.Rows Dim item As New listItem With item .code = common.getString(rec("code")) .name = common.getString(rec("name")) .bill = common.getInt(rec("bill")) .deposit = common.getInt(rec("deposit")) .commission = common.getInt(rec("commission")) 'difference = bill - (deposit + commission) 'この処理をdeposit もしくは commission に値が入ったことでイベントを発生させ計算を行いたい End With dataList.Add(item) Next End Sub End Class Public Class listItem 'コード Public Property code As String = "" '名称 Public Property name As String = "" '請求額 Public Property bill As Integer = 0 '入金額 Public Property deposit As Integer = 0 '手数料 Public Property commission As Integer = 0 '回収残 Public Property difference As Integer = 0 End Class