views:

552

answers:

1

Bound GetChanges always returns something when bound to a usercontrol's property (even on a simple one)

i have made a usercontrol, for some reason unknownst to me, when i bound a datacolumn to my control's property the dataSet1.GetChanges() always return something, even the column bound to my control was not changed.

what's the possible cause why GetChanges always return something?

here's a simple snippet to reproduce the binding/GetChanges problem:


using System;

using System.Data;

using System.Windows.Forms;

namespace BindingBug {

public partial class Form1 : Form
{

    DataSet _ds = new DataSet();

    void GetData()
    {           
        var t = new DataTable
        {
            TableName = "beatles",
            Columns =
            {
                {"lastname", typeof(string)},
                {"firstname", typeof(string)},
                {"middlename", typeof(string)}
            }
        };


        t.Rows.Add("Lennon", "John", "Winston");
        t.Rows.Add("McCartney", "James", "Paul");

        _ds.Tables.Add(t);            
    }

    public string Hey { set; get; }

    public Form1()
    {
        InitializeComponent();

        var tLastname = new TextBox { Top = 100 };
        var tFirstname = new TextBox { Top = 130 };

        this.Controls.Add(tLastname);
        this.Controls.Add(tFirstname);

        GetData();


        tLastname.DataBindings.Add("Text", _ds.Tables["beatles"], "lastname");
        tFirstname.DataBindings.Add("Text", _ds.Tables["beatles"], "firstname");

        // if the following line is commented 2nd:Has Changes == false
        this.DataBindings.Add("Hey", _ds.Tables["beatles"], "middlename");


        _ds.AcceptChanges();


        MessageBox.Show("1st:Has Changes = " + _ds.HasChanges().ToString()); 

        var bDetectChanges = new Button { Top = 160, Text = "Detect Changes" };
        bDetectChanges.Click += 
            delegate 
            {
                this.BindingContext[_ds.Tables["beatles"]].EndCurrentEdit();
                MessageBox.Show("2nd:Has Changes = " +  (_ds.GetChanges() != null).ToString()); 
            };

        this.Controls.Add(bDetectChanges);

    }    
}

} //namespace BindingBug

+1  A: 

i was able to solve the problem today, the key thing is to make the BindingContext's EndCurrentEdit aware if the value really changed. for this, we must implement System.ComponentModel.INotifypropertychanged on our control. i just saw the solution from here: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx

hope this can help others implementing their own controls which flag wrong change status on GetChanges()

public partial class Form1 : Form, System.ComponentModel.INotifyPropertyChanged
{
    //----------- implements INotifyPropertyChanged -----------


    // wish C# has this VB.NET's syntactic sugar
    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; // implements INotifyPropertyChanged.PropertyChanged 

    //----------- start of Form1  ----------


    DataSet _ds = new DataSet();



    void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }



    void GetData()
    {

        var t = new DataTable
        {
            TableName = "beatles",
            Columns =
            {
                {"lastname", typeof(string)},
                {"firstname", typeof(string)},
                {"middlename", typeof(string)}
            }
        };


        t.Rows.Add("Lennon", "John", "Winston");
        t.Rows.Add("McCartney", "James", "Paul");

        t.Columns["middlename"].DefaultValue = "";

        _ds.Tables.Add(t);            
    }



    string _hey = "";
    public string Hey 
    { 
        set 
        {
            if (value != _hey)
            {
                _hey = value;
                NotifyPropertyChanged("Hey");
            }
        } 
        get 
        {                

            return _hey;  
        } 
    }



    public Form1()
    {
        InitializeComponent();



        var tLastname = new TextBox { Top = 100 };
        var tFirstname = new TextBox { Top = 130 };

        this.Controls.Add(tLastname);
        this.Controls.Add(tFirstname);

        GetData();



        tLastname.DataBindings.Add("Text", _ds.Tables["beatles"], "lastname");
        tFirstname.DataBindings.Add("Text", _ds.Tables["beatles"], "firstname");

        this.DataBindings.Add("Hey", _ds.Tables["beatles"], "middlename");


        _ds.AcceptChanges();




        MessageBox.Show("1st:Has Changes = " + _ds.HasChanges().ToString());

        var bDetectChanges = new Button { Top = 160, Text = "Detect Changes" };
        bDetectChanges.Click +=
            delegate
            {
                this.BindingContext[_ds.Tables["beatles"]].EndCurrentEdit();
                MessageBox.Show("2nd:Has Changes = " + (_ds.GetChanges() != null).ToString());

            };

        this.Controls.Add(bDetectChanges);

    }

}
Michael Buen