Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

More BindingSource WinForm Databinding frustrations


:P
On this page:

I'm once again getting stuck on WinForm DataBinding. I work primarily with forms that bind to entity business objects so the thing I do a lot of is binding textboxes, checkboxes etc. to business object properties. The new BindingSource object in VS.NET makes this relatively easy.

 

  1. You drop a BindingSource object on the form
  2. You add a Project DataSource and point it the Entity object
  3. Note that the object must have properties not fields to bind to
  4. You then add the data mapping to the control
  5. Do this in DataBindings (Advanced)
  6. You specify the property of the control (ie. Text)  to map a property of the entity (ie. cCustomerEntity.FirstName)
  7. This binding is a mapping to a specific type
  8. You specify how the control update (OnValidation, OnPropertyChange)
  9. When all your bindings are hooked to controls you bind the actual data source object:
    this.MyBindingSource.DataSource = this.CustomerEntity;
    in code.

and you start binding with the entity and controls kept in sync. All of this works well. As I mentioned in a previous entry when I was struggling <g>, the actual databinding mechanics are much nicer in .NET 2.0 where. For one the new controls manage typed values much nicer with some basic inputmasking to match the type. So numerics right align and don't allow entering non-numeric data for example.

 

So far so good…

 

Custom Control Binding - Another story 

But I now have yet another problem. I have a custom wwDateTimeDisplay control, that allows editing both Date and Time in a single control on a form. It's a composite control that includes a custom DateTimePicker and a plain textbox for the time. There's a Value property which looks like this:

 

/// <summary>

/// The DateTime value that the control displays

/// </summary>

[Bindable(true)]

public DateTime Value

{

      get {

            this._Value = this.GetDate();

            return _Value;

            }

      set {

        if (value != _Value && this.ValueChanged != null)

            this.ValueChanged(this,EventArgs.Empty);

 

            _Value = value;

            this.SetDate(_Value);

            }

}

private DateTime _Value;

 

protected DateTime GetDate()

{

      DateTime Date = this.txtDate.Value;

     

      string DateString = Date.ToString("d") + " " + this.txtTime.Text.Trim();

      DateTime dt = DateTime.Parse(DateString);

 

      return dt;

}

protected void SetDate(DateTime CurrentDateTime)

{

      this.txtDate.Value = CurrentDateTime.Date;                 

      this.txtTime.Text = CurrentDateTime.ToString("t");

}

 

The control inherits UserControl and it works just fine to display and update date time values on a form.

 

But I cannot get this control to work correctly with DataBinding. If I set up DataBinding to the control using a BindingSource and using:

 

this.txtTimeIn.DataBindings.Add(new Binding("Value", this.bindEntry, "Timein", true));

 

I get inbound binding to work perfectly, but the binding never updates the underlying object (CustomerEntity.Timein).

 

I do see OnValidate fire in the object which should be the hook that the BindingSource is using. But the Entity Property is not updated.

 

 

I'm probably missing something obvious, but after searching around for an hour today and running into lots of small pieces I still haven't found a resource that explains how the BindingSource actually hooks up the values. Specifically what triggers the OnValidation or OnPropertyChanged operations that presumably update the control and underlying data sources.

 

Anybody know of a good resource?


The Voices of Reason


 

ParanoidPenguin
January 12, 2006

# re: More BindingSource WinForm Databinding frustrations


Rick Strahl
January 12, 2006

# re: More BindingSource WinForm Databinding frustrations

Cool... The correct url is:

http://www.windowsforms.net/Samples/Go%20To%20Market/Data%20Binding/DataBinding%20FAQ.doc

Hmmm... looked this over. I've already been implementing a ValueChanged event unbeknownst to the fact that this is supposed to provide the change notifications. This doesn't seem to work. Implementing INotifyPropertyChange does the trick though.

INotifyPropertyChange seems to update the control values. However, looks like I have another related problem now though:

I can't seem to find an event to hook to do the dynamic calculations where the Entity object is already updated. I'm using the Validated and in this event the Entity is not updated. Again it's only the UserControl that exhibits this behavior - the stock controls work fine here. <sigh>

steve
January 13, 2006

# re: More BindingSource WinForm Databinding frustrations

With the flock of Borland engineers that have gone to MS over the years I am a little surprised that Winforms databinding is so lame.

Databinding in Delphi was always a pleasure to work with, even in Delphi I (1994).

Duray AKAR
February 22, 2006

# re: More BindingSource WinForm Databinding frustrations

did you find a solution for that ?

I have a similar issue...

I am using a UserControl, which is supposed to load another dataset automatically when a Bindable Property is updated... such as :

public class myUserControl: Usercontrol
{
private string myKey = "";
[Bindable(true)]
public sting Key
{
get{return myKey;}
set
{
myKey = value;
LoadDataByKey();
}
}

public void LoadDataByKey()
{
// Load the dataset here
}

}


Then I add this control to my Form, which hosts a BindingSource, a Dataset and a datagridview.

Then I bind the "Key" property of my UserControl to one of the properties in the bindingsource.

When I run my application, the LoadDataByKey method is called 5 times...

When I add the usercontrol to the page in the designer, the designer assigns a default value to it, so that is the first time, which I can (kind of) avoid...

Then during the initial databinding to the empty dataset, my method gets called 2 times... However, the values are null, because the current value of the bindingsource is null at that point...

On the form load, I load my dataset on the form using a backgroundworker, and the method gets called 2 more times when I get my dataset loaded...

Interestingly, when I change the position of the Bindingsource by moving to another row on the form, the method gets called only ONCE, which I LOVE :)

Any ideas or suggestions?

Thanks in advance...

Christopher M. Lauer
May 24, 2006

# re: More BindingSource WinForm Databinding frustrations

Good morning: I am having a similar problem in binding an objects System.Nullable(Of DateTime)) property to a standard winForm DatePicker. As with you, I find the 2005 databinding a welcomed improvement to yesteryears hell way of binding but this datepicker is brining back teriable memeories!

I have the datepicker box reading from the property just fine, it just won’t write back to it! Got an idas as to why?

Objects Property:
Public Property EndDate() As System.Nullable(Of DateTime)
Get
Return _enddate
End Get
Set(ByVal value As System.Nullable(Of DateTime))
If Not System.Nullable(Of DateTime).Equals(value, EndDate) Then
MyBase.IsDirty = True
_enddate = value
RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("EndDate"))
End If
End Set
End Property

Data Binding:


Dim bEnd As New Binding("Value", _policyManager, "EndDate")
AddHandler bEnd.Format, AddressOf NullDateWrite_Format
AddHandler bEnd.Parse, AddressOf NullDateRead_Format
Me.dtEnd.DataBindings.Add(bEnd)

Dim bEndNullable As New Binding("Checked", _policyManager, "EndDate")
AddHandler bEndNullable.Format, AddressOf NullBinding_Format
dtEnd.DataBindings.Add(bEndNullable)

Private Sub NullBinding_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
e.Value = Not (e.Value Is Nothing)
End Sub

Private Sub NullDateWrite_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
If e.Value Is Nothing Then
e.Value = Date.Today
End If
End Sub

Private Sub NullDateRead_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
'Code here for debug use, e.value contains the user selected date but it is never
' written back to the object?!
e.Value = DirectCast(e.Value, System.Nullable(Of DateTime))
End Sub



Christopher M. Lauer
May 24, 2006

# re: More BindingSource WinForm Databinding frustrations

Hello all, I believe I have solved the binding a System.Nullable(Of DateTime) property to a DateTimePicker (that allows for Nulls; DateTimePicker.ShowCheckBox = true). I am not saying that this is the ideal way to do it but it works! If anyone would like to comment on a better way please let me know.

The key was adding the bolded “, True, DataSourceUpdateMode.OnPropertyChanged” to the Binding (this allows the datePicker to update the property. HOWEVER, this does not update the property if the user selects NULL as the date. To update the property with NULL I had to add the second handler call to the NullDateRead_Format method. I am checking the checked property of the DateTimePicker, if not checked then I set e.value to system.DBNull.value.

I am sure this is a “cleaner” way to do this but for now I am just happy it works! Please let me know if you find a cleaner or better way.


Private Sub SetupBindings()
Dim bEnd As New Binding("Value", _policyManager, "EndDate", True, DataSourceUpdateMode.OnPropertyChanged)
AddHandler bEnd.Format, AddressOf NullDateWrite_Format
AddHandler bEnd.Parse, AddressOf NullDateRead_Format
Me.dtEnd.DataBindings.Add(bEnd)

Dim bStart As New Binding("Value", _policyManager, "StartDate", True, DataSourceUpdateMode.OnPropertyChanged)
AddHandler bStart.Format, AddressOf NullDateWrite_Format
AddHandler bStart.Parse, AddressOf NullDateRead_Format
Me.dtStart.DataBindings.Add(bStart)

Dim bStartNullable As New Binding("Checked", _policyManager, "StartDate")
AddHandler bStartNullable.Format, AddressOf NullBinding_Format
dtStart.DataBindings.Add(bStartNullable)

Dim bEndNullable As New Binding("Checked", _policyManager, "EndDate")
AddHandler bEndNullable.Format, AddressOf NullBinding_Format
dtEnd.DataBindings.Add(bEndNullable)
End Sub

Private Sub NullBinding_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
e.Value = Not (e.Value Is Nothing)
End Sub

Private Sub NullDateWrite_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
If e.Value Is Nothing Then
e.Value = Date.Today
End If
End Sub

Private Sub NullDateRead_Format(ByVal sender As Object, ByVal e As ConvertEventArgs)
If Not DirectCast(DirectCast(sender, System.Windows.Forms.Binding).BindableComponent, DateTimePicker).Checked Then
e.Value = System.DBNull.Value
End If
End Sub

Object Property:

Public Property StartDate() As System.Nullable(Of DateTime)
Get
Return _startdate
End Get
Set(ByVal value As System.Nullable(Of DateTime))
If Not System.Nullable(Of DateTime).Equals(value, StartDate) Then
MyBase.IsDirty = True
_startdate = value
RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("StartDate"))
End If
End Set
End Property



# DotNetSlackers: More BindingSource WinForm Databinding frustrations


Warren J. Hairston
November 27, 2006

# re: More BindingSource WinForm Databinding frustrations

I was having a similar problem, but resolved it by explicitly stating the DataSourceUpdateMode in the databinding as follows:

this.txtTimeIn.DataBindings.Add(new Binding("Value", this.bindEntry, "Timein", true, DataSourceUpdateMode.OnPropertyChanged));


Although it's buried in the documentation, it's not obvious that the default for DataSourceUpdateMode is OnValidation, and validation only occurs if the object is updated via the control's user interface, not when the value is changed via code.

I opened up an issue on Microsoft's http://connect.microsoft.com site under the Visual Studio/.NET section with ID#240723 with much more detail if you're interested.

Bas Hamer
November 29, 2006

# re: More BindingSource WinForm Databinding frustrations

Thanks Warren, this fixed my issue.

I had a bound datepicker on a seperate tab. if I made a change before visiting the tab i started getting all sorts of interesting first chance exceptions. If I visited the tab w/ the datepickers first all was working fine.

this was driving me up the wall for a good couple of hours, thanks again for posting this.

Bas

Edgar
December 15, 2006

# re: More BindingSource WinForm Databinding frustrations

I have a worst problem (I guess)...

I need to develop an user control (MTblStadr) with a datagridview, the problem si that Idon't know how to do for the MTblStadr control be able to asign a datasource in design time...

I'm sorry if is confuse my question. My english is'nt so good.

Michael L Perry
November 03, 2007

# re: More BindingSource WinForm Databinding frustrations

You might be interested in this alternative to data binding. Instead of setting properties, you handle events that call your own business logic. When the data that your code accesses changes, the controls fire the event again to update themselves automatically.

http://updatecontrols.net

david
January 09, 2008

# re: More BindingSource WinForm Databinding frustrations

It works for me simply adding :
txtField.DataBindings(0).NullValue = ""

where databindings(0) is the binding of text to a Bindingsource of a field type Date.

Sorry for my bad english

Hetal
June 18, 2008

# re: More BindingSource WinForm Databinding frustrations

Thanks Warren. Your suggestion fixed my issue.

I truely appreciate you sharing with the community.

Torsten Tiedt
October 26, 2010

# re: More BindingSource WinForm Databinding frustrations

Hi,

please not that you can use the following method of the bindingsource to udpate the bound controls on a form:

BindingSource.ResetCurrentItem()

In my case, I also set the "DataSourceUpdateMode.OnPropertyChanged" during binding of the controls.

Cheers,

Torsten

Andrew
December 09, 2010

# re: More BindingSource WinForm Databinding frustrations

Just spent a day finding that adding a ValueChanged event to a working data-bound UserControl messes with the write-back binding.

I use a BindingSource bound to a strongly-typed DataSet, then bind the UserControl to the BindingSource.

If you use MS's example http://msdn.microsoft.com/en-us/library/ms171926%28v=vs.80%29.aspx it works fine until you define an event on the UserControl:

Public Event ValueChanged(ByVal sender As Object, ByVal e As EventArgs)

FYI I'm working in VS2005 against DNF2 on Win7 - haven't checked other variations yet.

HTH

Dan Groft
October 20, 2011

# re: More BindingSource WinForm Databinding frustrations

Rick:

I'm having the same problem that you were having five years ago, in which (on a custom user control) the inbound binding works perfectly, but the BindingSource never updates the underlying object. You implemented INotifyPropertyChanged? Where? My underlying object already implements this interface and fires the PropertyChanged event when properties are changed.

Below is some code that hopefully illustrates how I have things set up.

public MyObject : INotifyPropertyChanged
{
    // Imagine several properties here that fire PropertyChanged
    // when their setters are called.
}
 
public partial class MyControl : UserControl
{
    private readonly BindingSource bs;
 
    public MyControl()
    {
        bs = new BindingSource();
 
        // Set up the binding.
        myDateTimePicker.DataBindings.Add("Value", bs, "StartDate", true, DataSourceUpdateMode.OnPropertyChanged);
    }
 
    public MyObject MyObject
    {
        get { return bs.DataSource as MyObject; }
        set { bs.DataSource = value; }
    }
}
 
...
 
MyObject myObject = new MyObject() { /* initialize properties here */ }
MyControl myControl = new MyControl() { MyObject = myObject };
 
myControl.Show();


While the user control is showing, the controls on the form show the correct values pulled from the myObject instance. But, these changes don't seem to ever make it to the underlying object. At this point, the property values in myControl.MyObject.* are unchanged.

This has had me stumped for days. Thank you in advance for any help/insight you can provide.

Dan Groft
October 24, 2011

# re: More BindingSource WinForm Databinding frustrations

Regarding my earlier post, my colleague uncovered the underlying problem. It isn't mentioned in the earlier post, but the class MyObject also implements IEnumerable<T>. As such, the binding mechanism was automatically fetching the enumerator and binding the form to the first item. Isolating the enumerable to a property on MyObject not only fixed the problem, but is -- in my opinion -- a cleaner implementation.

So, instead of:
public class MyObject : IEnumerable<MyItem>
{
    public IEnumerator<MyItem> GetEnumerator()
    {
        return new MyItemEnumerator(this);
    }
}


I now have:
public class MyObject
{
    public IEnumerable<MyItem> MyItems
    {
        return new MyItemEnumerator(this);
    }
}

Badr
June 30, 2013

# re: More BindingSource WinForm Databinding frustrations

#Warren just there is another solution which I have look for couple of hours, You may just select another form control and keep the default value for DataSourceUpdateMode = OnValidation,
So to validate a binding control you shouldn't use [OtherControl].Focus() which doesn't work for this case, but instead use [OtherControl].Select()
I prefer this solution because some projects have couple of forms which each one has couple of data controls, so it's boring to change it's DataSourceUpdateMode to OnPropertyChange and maybe you may forget some controls, ;)
another thing (IMHO) OnPropertyChange impact negatively on performance, coz each time you type in the data control the data source is updated, alternatively OnValidation the data source is updated one time when the control is validated which mean when it loses the focus!!

Ken
October 18, 2016

# re: More BindingSource WinForm Databinding frustrations

Your statement was:

"I get inbound binding to work perfectly, but the binding never updates the underlying object (CustomerEntity.Timein).

I do see OnValidate fire in the object which should be the hook that the BindingSource is using. But the Entity Property is not updated."

You may have forgot to call:

BindingSource.EndEdit()

in your validation event or somewhere after the update of the text but before the call to save the entity to the db.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024