Groups | Blog | Home
all groups > dotnet windows forms databinding > january 2007 >

dotnet windows forms databinding : INotifyPropertyChanged Bug ?


John Greenwood
1/24/2007 7:15:00 AM
Hi,

I'm not sure if i'm misunderstanding how INotifyPropertyChanged should
work but it's not working as I expected.

I have a sample program with a very simple 'Customer' class with three
properties code, name & address. All these are bound to a form via a
BindingSource and fire the PropertyChanged event when the property is
modified.

I change one of these properties in code and find that all of the
properties are fetched and rebound to the form. Is this correct ?
What's the point of specifying a property name in the
PropertyChangedEventArgs if all the controls are rebound anyway.

Any help would be much appreciated

John

If it's any help my code is below

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace NotifyChange
{
public partial class Form1 : Form
{
private Customer _customer;

public Form1()
{
InitializeComponent();
_customer = new Customer();
_customer.Code = "G001";
_customer.Name = "Greenwood Enterpises Ltd";
_customer.Address = "128 Smithey Road";
customerBindingSource.DataSource = _customer;
}

private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("<-- Change Code --");

_customer.Code = "F001";

Console.WriteLine("-- Change Code -->");
}

private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine("<-- Change Name --");

_customer.Name = "Fletcher Business Services Ltd";

Console.WriteLine("-- Change Name -->");
}

}

public class Customer : INotifyPropertyChanged
{

private string _code = "";
private string _name = "";
private string _address = "";

public string Code
{
get
{
Console.WriteLine("Got 'Code' at {0}", DateTime.Now);
return _code;
}
set
{
if (_code != value)
{
_code = value;

NotifyPropertyChanged(" Code");
}
}
}

public string Name
{
get
{
Console.WriteLine("Got 'Name' at {0}", DateTime.Now);
return _name;
}
set
{
if (_name != value)
{
_name = value;

NotifyPropertyChanged("Name");
}
}
}

public string Address
{
get
{
Console.WriteLine("Got 'Address' at {0}",
DateTime.Now);
return _address;
}
set
{
_address = value;
}
}

private void NotifyPropertyChanged(string Name)
{

if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(Name));
}
}
#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

#endregion
Bart Mermuys
1/24/2007 3:28:43 PM
Hi,

[quoted text, click to view]

Yes it is. Any property changed event will result in
BindingManagerBase.PushData which causes a PushData on *all* its Bindings.

[quoted text, click to view]

When it comes to WinForms databinding there is no point afaik. But
remember that INotifyPropertyChanged can be used elsewhere too, eg. for the
PropertyGrid (dunno if it refreshes all properties on change there) and also
for WPF (where it doesn't refresh all properties on change).

HTH,
Greetings


[quoted text, click to view]

John Greenwood
1/25/2007 6:57:11 AM
Hi Bart,

Some of the properties on my class were totals built dynamically every
time they were accessed and so of course were being rebuilt every
time another property from the same class issued the change event.

At least now I know and I can avoid similar situations in the future.

Cheers

John


On Wed, 24 Jan 2007 15:28:43 GMT, "Bart Mermuys"
[quoted text, click to view]
Doug Crawford
2/27/2007 8:17:30 PM
[quoted text, click to view]
I am also having problems with this. The objects in my BindingList
implement INotifyPropertyChange. If I use the Windows Forms designer to
layout the BindingSource as a DataGridView things look pretty good. If
my objects change I see the changes in the grid. But If I start
editing a cell I must complete the edit very quickly or I risk having
the BindingManagerBase.PushData() reset my edit to the previous value.
Is there anyway to prevent the BindingSource from reseting a
DataGridView cell while I am in the middle of editing when a different
property triggers a BindingManagerBase.PushData()?

Thanks,
RobinS
2/28/2007 2:36:41 PM
I'm assuming when you say you implemented INotifyPropertyChanged, you
implemented it on the Customer Class. Did you also implement
IEditableObject, and put in the code to save the original values, then
populate them if the insert/udpate was cancelled?

I have a DGV bound to a list of business objects and I'm not having any of
these problems with it.

Robin S.
Ts'i mahnu uterna ot twan ot geifur hingts uto.
-----------------------------------------------
[quoted text, click to view]

Doug Crawford
2/28/2007 4:13:23 PM
Yes, if we follow the example in this thread I implemented
INotifyPropertyChanged on the Customer class. I did not implement
IEditableObject, but I am not sure that is going to help. My main
problem is that any change to an individual property in the Customer
class causes the binding mechanism to globally push all of the Customer
Properties to the Form controls (The property string name in the
PropertyChangedEventArgs appears to be ignored).

So lets say you are editing Customer.Name in the DataGridView and while
you are editing something else changes Cusomter.Code in the data source.
I was hoping to just see the cell under the Code column change, but
actually all of the columns in the selected record are updated including
the cell I am currently editing.

Maybe I should be implementing IEditableObject and prevent the Customer
class from triggering the PropertyChanged event until the edit is complete.

Will my Customer.BeginEdit() method be called when a user starts editing
a TextBox that is databound to a Customer property, or does this
mechanism only work with the DataGridView?

Doug



[quoted text, click to view]
RobinS
2/28/2007 9:11:01 PM
I think the BeginEdit/EndEdit/CancelEdit methods could help you. I think
BeginEdit applies to any control, not just to a DGV.

What else is changing your data source? Is it the same user, or some other
user? How are they changing your business object?

You could also un-implement INotifyPropertyChanged; I don't know what other
ramifications this would have, though.

Robin S.
---------------------------------------------
[quoted text, click to view]
Doug Crawford
3/1/2007 9:55:38 AM
My "business object" is not really the traditional use case of a
Customer row in a database. It is more analogous to real time status
data with just one editable property.

I did discover that if I toggle the value of the RaiseListChangedEvents
property on the BindingSource I can temporarily suppress change
notifications, so I think this approach will work.

Doug

[quoted text, click to view]
RobinS
3/1/2007 10:40:38 AM
Cool. I'm glad you found a way to get it to work.
Robin S.
---------------------------
[quoted text, click to view]
AddThis Social Bookmark Button