при изменении FxRate поля Total должны автоматически обновляться.
DataColumn.Expression
не предоставляет способ ссылки на внешние переменные.Однако вы можете обновить выражение в любое время.
Вам нужно будет вызвать метод обновления, когда FxRate
изменится.Если FxRate
является свойством, вы можете вызвать метод update из его метода установки.
Изменения в выражении не будут автоматически отражаться в связанном элементе управления.Метод обновления также должен указать привязкам для обновления.Если вы выполняете привязку через экземпляр BindingSource
, вызовите его метод ResetBindings(False)
.Если вы выполняете привязку непосредственно к методу DataTable, a more complex method would be to obtain the
DataTable 's
CurrencyManager and call its
Refresh`.
Предполагая, что переменная DataTable
имеет имя dt
, следующий код получит CurrencyManager
;Me
относится к содержащему Form
.
Dim mngr As CurrencyManager = CType(Me.BindingContext.Item(dt), CurrencyManager)
mngr.Refresh()
Редактировать: рабочий пример с использованием BindingSource, как было запрошено в комментариях.
Вновый проект WinForm, замените содержимое Form1.vb следующим кодом (все элементы управления создаются этим кодом - без поддержки дизайнера).
Код создает: TextBox
для изменения поля «Количество», Label
для отображения поля «Всего», NumericUpDown
для изменения значения свойства FxRate
и две кнопки, чтобы разрешить навигацию по записям в DataTable
.
. DataTable
имеет три записи. Запись состоит из двух полей «Количество» и «Всего». «Всего» будет вычислено какпроизведение свойства формы FxRate и поля «Количество», устанавливая свойство Expression
столбца «Количество» при каждом изменении FxRate
.
Public Class Form1
Inherits Form
Private tbInput As TextBox
Private lblTotal As Label
Private nudFxRate As NumericUpDown
Private btnNext As Button
Private btnPrevious As Button
Private bs As BindingSource
Private _FxRate As Int32
Private dt As DataTable
Public Sub New()
MyBase.New()
SetupControls()
dt = New DemoTable ' create a preconfigured DataTable
bs = New BindingSource(dt, Nothing)
SetBindings()
FxRate = 5
AttachControlEventHandlers()
End Sub
Public Property FxRate As Int32
Get
Return _FxRate
End Get
Set(value As Int32)
If value <> _FxRate Then
_FxRate = value
UpdateTotalExpression() ' only update the Expression if the value changes
End If
End Set
End Property
Private Sub UpdateTotalExpression()
' Change the expression to reflect the current value of FxRate
Dim totalColumn As DataColumn = dt.Columns("Total")
totalColumn.Expression = $"[Quantity] * {FxRate}"
' Expression changes do not notify the BindingSource of value changes
' so tell the BindingSource to reload all values
bs.ResetBindings(False)
End Sub
Private Sub tbInput_KeyPress(sender As Object, e As KeyPressEventArgs)
If e.KeyChar = Convert.ToChar(Keys.Enter) Then
Me.Validate() ' force tbInput to Validate
e.Handled = True ' eat the enter key
End If
End Sub
Private Sub tbInput_Validated(sender As Object, e As EventArgs)
' if tbInput successfully validated, push the values in the BindingSource to the DataTable
bs.EndEdit() ' push the editted value to the DataTable, causing Total to update
End Sub
Private Sub SetBindings()
' Update BindingSource once tbInput Validates successfully
tbInput.DataBindings.Add("Text", bs, "Quantity", True, DataSourceUpdateMode.OnValidation)
' lblTotal never updates the BindingSource
lblTotal.DataBindings.Add("Text", bs, "Total", True, DataSourceUpdateMode.Never)
' nudFxRate updates the FxRate property
nudFxRate.DataBindings.Add("Value", Me, "FxRate", True, DataSourceUpdateMode.OnPropertyChanged)
End Sub
Private Sub SetupControls()
tbInput = New System.Windows.Forms.TextBox()
lblTotal = New System.Windows.Forms.Label()
nudFxRate = New System.Windows.Forms.NumericUpDown()
btnNext = New System.Windows.Forms.Button()
btnPrevious = New System.Windows.Forms.Button()
CType(nudFxRate, System.ComponentModel.ISupportInitialize).BeginInit()
SuspendLayout()
'
'tbInput
'
tbInput.Location = New System.Drawing.Point(27, 40)
tbInput.Name = "tbInput"
tbInput.Size = New System.Drawing.Size(100, 22)
tbInput.TabIndex = 0
'
'lblTotal
'
lblTotal.AutoSize = False
lblTotal.BackColor = Color.Yellow
lblTotal.Location = New System.Drawing.Point(299, 42)
lblTotal.Name = "lblTotal"
lblTotal.Size = New System.Drawing.Size(100, 17)
lblTotal.TabIndex = 1
lblTotal.Text = "0"
'
'nudFxRate
'
nudFxRate.Location = New System.Drawing.Point(28, 94)
nudFxRate.Name = "nudFxRate"
nudFxRate.Size = New System.Drawing.Size(120, 22)
nudFxRate.TabIndex = 3
nudFxRate.Value = 5
'
'btnNext
'
btnNext.Location = New System.Drawing.Point(27, 136)
btnNext.Name = "btnNext"
btnNext.Size = New System.Drawing.Size(75, 23)
btnNext.TabIndex = 4
btnNext.Text = "Next"
btnNext.UseVisualStyleBackColor = True
'
'btnPrevious
'
btnPrevious.Location = New System.Drawing.Point(28, 171)
btnPrevious.Name = "btnPrevious"
btnPrevious.Size = New System.Drawing.Size(75, 23)
btnPrevious.TabIndex = 5
btnPrevious.Text = "Previous"
btnPrevious.UseVisualStyleBackColor = True
'
'Form1
'
AutoScaleDimensions = New System.Drawing.SizeF(8.0!, 16.0!)
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
ClientSize = New System.Drawing.Size(800, 450)
Controls.Add(btnPrevious)
Controls.Add(btnNext)
Controls.Add(nudFxRate)
Controls.Add(lblTotal)
Controls.Add(tbInput)
Name = "Form1"
Text = "Form1"
CType(nudFxRate, System.ComponentModel.ISupportInitialize).EndInit()
ResumeLayout(False)
PerformLayout()
End Sub
Private Sub AttachControlEventHandlers()
AddHandler btnNext.Click, Sub() bs.MoveNext() ' move to next record in bindingsource
AddHandler btnPrevious.Click, Sub() bs.MovePrevious() ' move to previous record in bindingsource
AddHandler tbInput.KeyPress, AddressOf tbInput_KeyPress ' allow enter key to validate textbox
AddHandler tbInput.Validated, AddressOf tbInput_Validated ' update bindingsource on validation
End Sub
Private Class DemoTable : Inherits DataTable
Public Sub New()
Columns.Add("Quantity", GetType(Int32))
Columns.Add("Total", GetType(Int32))
Rows.Add(New Object() {10})
Rows.Add(New Object() {20})
Rows.Add(New Object() {30})
End Sub
End Class
End Class