0

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.

KevenDenen
  • 1,718
  • 13
  • 25

1 Answers1

2

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
TnTinMn
  • 11,522
  • 3
  • 18
  • 39