David
David

Reputation: 6131

DataBinding - Toggle Enabled Based on Input

I'm using Visual Basic .NET developing a windows form application and I want to toggle the enabled property of a Button based on if there is anything in a TextBox. I attempted to setup the DataBinding using the following:

ButtonBack.DataBindings.Add("Enabled", Me.TextBoxValue, "TextLength")

This successfully disables the Button, but whenever anything is typed in the TextBox, the Button never gets enabled. I would much rather do this via DataBindings if possible as opposed to setting the Enabled property manually in the TextChanged or Validating event of the TextBox.

Upvotes: 0

Views: 1004

Answers (2)

Luc Morin
Luc Morin

Reputation: 5380

I usually implement this kind of custom property binding by "subclassing" the control that requires the "new" property, as in your case, TextBox needs an HasLength Boolean property (or whatever name you want to give it).

Here's MyTextBox.vb:

Public Class MyTextBox
    Inherits TextBox

    Public Event HasLengthChanged As EventHandler

    Private _HasLength As Boolean
    Public Property HasLength() As Boolean
        Get
            Return _HasLength
        End Get
        Set(ByVal value As Boolean)
            If value <> _HasLength Then
                _HasLength = value
                OnHasLengthChanged()
            End If
        End Set
    End Property

    Public Sub New()
        _HasLength = False
    End Sub

    Protected Sub OnHasLengthChanged()
        RaiseEvent HasLengthChanged(Me, New EventArgs())
    End Sub

    Protected Overrides Sub OnTextChanged(e As EventArgs)
        MyBase.OnTextChanged(e)
        HasLength = Not (String.IsNullOrEmpty(Text))
    End Sub
End Class

And here's Form1.vb:

Public Class Form1

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)

        ButtonBack.DataBindings.Add("Enabled", Me.MyTextBox1, "HasLength", True, DataSourceUpdateMode.OnPropertyChanged)

    End Sub

End Class

Of course, you need a Form with a MyTextBox instance and a regular Button instance.

With this method, as soon as the user types something in the textbox, the button becomes enabled, and as soon as the textbox becomes empty, the button is disabled. Please note that I used the DataSourceUpdateMode.OnPropertyChanged so that the update is done as you type, and not only when the textbox loses focus.

EDIT: I thought I'd add a bit of background about the PropertyNameChanged pattern in .NET.

There are different ways to let observers know that a property has changed on an object, and most of the time we use the INotifyPropertyChanged interface, but for controls, the recommended method is still to use the PropertyNameChanged pattern, which is recognized by .NET, and thus the Binding object can do its job and know when the desired property has changed.

INotifyPropertyChanged is recommended for data objects that participate in binding.

By the way, the PropertyNameChanged works in both Windows Forms and WPF.

As reference MSDN:

https://learn.microsoft.com/en-us/dotnet/framework/winforms/how-to-apply-the-propertynamechanged-pattern

EDIT 2: I'm a C# programmer, and I've done my best to apply the residual knowledge that I have of VB.NET. Any error is really the result of my being too rusty in VB. Sorry for any inconvenience, but I can assure you that the code runs just fine here.

Upvotes: 2

TnTinMn
TnTinMn

Reputation: 11801

As @LarsTech stated in his comment, you need to use a property of the TextBox Class that raises changed notifications. The Text property is the appropriate one to use.

Your request to do this strictly via the binding is possible, but it will still involve using an event handler. As such, I don't see much value in this approach over handling the TextBoxValue.TextChanged event.

One way of doing this is to use the Binding.Format Event to convert the string of the Text Property to a boolean based on if it contains any characters.

Dim b As Binding = ButtonBack.DataBindings.Add("Enabled", Me.TextBoxValue, "Text", True, DataSourceUpdateMode.OnPropertyChanged)
AddHandler b.Format, Sub(s As Object, args As ConvertEventArgs) args.Value = Not String.IsNullOrEmpty(CStr(args.Value))

Because the binding is two way, if your code changes the ButtonBack.Enabled property, it will send the string representation of the property back to TextBoxValue and its text will read either "True" or "False". This would not be a desirable consequence. To rectify this possibility, the Binding.Parse Event will need to be handled.

AddHandler b.Parse, Sub(s As Object, args As ConvertEventArgs) args.Value = Me.TextBoxValue.Text

Upvotes: 1

Related Questions