I have a form with a few controls on it; some text boxes that are databound to a private form object's properties (Financial) and a DevExpress GridControl that is databound to a BindingList(of Fee) (Fees) property on the same Financial object. One of the properties on Financial is a readonly property that calculates some data based on other properties of the Financial and Fees (MonthlyCosts). Both Financial and Fee implement INotifyPropertyChanged.
The problem that I am having is that the textbox that is bound to that MonthlyCosts property does not update when changes are made to the GridControl. If I change the cost of a fee in the GridControl, then change a textbox value (Margin) that is also used in that calculation, the textbox with the calculated value will only update after I change the Margin.
Some of the related code is shown below:
Public Class Financial
Inherits BindableBase ' helper for INotifyPropertyChanged
Public Property Margin As Decimal
Get
return _margin
End Get
Set
SetProperty() ' INotifyPropertyChanged stuff
End Set
End Property
Public ReadOnly Property Fees As BindingList(Of Fee)
Public ReadOnly Property Total as Decimal
Get
return Fees.Sum(Function(fee) fee.Amount) / (1 - Margin)
End Get
End Property
End Class
Public Class Fee
Inherits BindableBase ' helper for INotifyPropertyChanged
Public Property Amount as Decimal
End Class
In the form:
' Setup the databindings
Margin.DataBindings.Add("EditValue", Financial, NameOf(Financial.Margin))
FeeGrid.DataBindings.Add("DataSource", Financial, NameOf(Financial.Fees))
Total.DataBindings.Add("EditValue", Financial, NameOf(Financial.Total))
The databindings all seem to work fine, except in the case of changing the Fees doesn't change the Total textbox. If I put a button that pops up the Total property in a MessageBox, it reports the correct Total, but the textbox is not updating. It seems like the NotifyPropertyChanged on the Fee object isn't getting propagated up through the BindingList to the Form to tell it to refresh the Total textbox.
The databindings all seem to work fine, except in the case of changing the Fees doesn't change the Total textbox.
There is nothing shown in your code that would raise the PropertyChanged
Event for property Total. With Total
being a computed value dependent on the properties Fees
and Margin
, changes to those properties should also raise a change notification for Total
.
As Fees
is declared as a BindingList(Of Fee), subscribing to its ListChanged Event will provide a means of notifying a change to Total
due to changes in Fees
.
The following is a working WinForm example similar to what you posted, but it uses only stock controls (TextBox, DataGridView, and Label).
Public Class BindableBase : Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub RaisePropertyChanged(<CallerMemberName> Optional PropName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropName))
End Sub
End Class
Public Class Financial : Inherits BindableBase
Public _margin As Decimal
Public Sub New()
Fees = New BindingList(Of Fee)
AddHandler Fees.ListChanged, AddressOf Fees_Changed
End Sub
Private Sub Fees_Changed(sender As Object, e As ListChangedEventArgs)
NotifyTotalChanged()
End Sub
Private Sub NotifyTotalChanged()
RaisePropertyChanged(NameOf(Me.Total))
End Sub
Public Property Margin As Decimal
Get
Return _margin
End Get
Set(ByVal value As Decimal)
If value <> _margin Then
_margin = value
RaisePropertyChanged()
NotifyTotalChanged() ' Margin affects Total
End If
End Set
End Property
Public ReadOnly Property Fees As BindingList(Of Fee)
Public ReadOnly Property Total As Decimal
Get
Return Fees.Sum(Function(fee) fee.Amount) / (1 - Margin)
End Get
End Property
End Class
Public Class Fee : Inherits BindableBase
Private _Amount As Decimal
Public Property Amount As Decimal
Get
Return _Amount
End Get
Set(value As Decimal)
If value <> _Amount Then
_Amount = value
RaisePropertyChanged()
End If
End Set
End Property
End Class
Example usage:
Public Class Form1
Private Financial As New Financial
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
SetFinancialBindings()
End Sub
Private Sub SetFinancialBindings()
Margin.DataBindings.Add("Text", Me.Financial, NameOf(Me.Margin))
FeeGrid.DataBindings.Add("DataSource", Me.Financial, NameOf(Me.Financial.Fees))
Total.DataBindings.Add("Text", Me.Financial, NameOf(Me.Financial.Total))
End Sub
End Class