简体   繁体   中英

C# WInForms TextBox DataBinding refresh TetxtBox.Text if bindings property change

class Class1
{
   public string val {get;set;}
}
Class1 cl;
private void Form1_Load(object sender, EventArgs e)
{
cl = new Class1();
            textBox1.DataBindings.Add("Text",cl,"val",false,DataSourceUpdateMode.OnPropertyChanged,);
            textBox2.DataBindings.Add("Text", cl, "val", false, DataSourceUpdateMode.OnPropertyChanged);
        }    


        private void button1_Click(object sender, EventArgs e)
        {
            cl.val += "11";
        }

I change value in textBox1, at textBox2 value changes immediatly too.
If I click button, bindings value cl.val changed from code, but both textBox value stay unchanged.
How to refresh data on textbox form if cl.val change from code?

PS: if after row
cl.val += "11"; - add
textBox1.Text = cl.val;
then value refresh at both textBoxs
why is that?

In order to make data binding work when data source property is changed by a code, the data source ( Class1 in your case) must provide some sort of a property change notification. The possible choices are events called PropertyNameChanged where PropertyName is the name of the property for which the change notification applies, or more general approach is to implement INotifyPropertyChanged Interface .

Here is an example using the second approach. Since the C# auto properties cannot be used anymore, people usually create a base class to reduce repetitive boilerplate code needed like this

public abstract class BindableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
    protected static bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

and then use it as follows

class Class1 : BindableObject
{
    private string _val;
    public string val
    {
        get { return _val; }
        set { SetProperty(ref _val, value); }
    }
}

Once you do this, everything will work as expected.

If as you said your class is auto generated by EF, then you need to create a wrapper class (usually referred as ViewModel) to be used for UI data binding. In general, DTOs, Entities etc. classes are not for direct use in the UI.

Update While all the above is the right way to go, for the sake of completeness, here is a quick and dirty approach.

Helper function:

public static class DataBindingUtils
{
    public static void RefreshBindings(this BindingContext context, object dataSource)
    {
        foreach (var binding in context[dataSource].Bindings.Cast<Binding>())
            binding.ReadValue();
    }
}

Sample usage:

private void button1_Click(object sender, EventArgs e)
{
    cl.val += "11";
    BindingContext.RefreshBindings(cl);
}

Try this:

cl.val+="11";
textBox1.ResetBindings();
textBox2.ResetBindings();


Update

The fact is that when you change the class value, you must notify the UI that the underlying data has changed, so you must implement INotifyPropertyChanged in your class. Define your class Class1 like this and try it:

class Class1:INotifyPropertyChanged
    {
        private string _val;
        public string val
        {
            get
            {
                return this._val;
            }
            set
            {
                if (this._val != value)
                {
                    this._val = value;
                    NotifyPropertyChanged("");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }


Update 2

As Ivan and me has explained, the way to do it is implementing INotifyPropertyChanged. But if you want a dirty way of doing it,you could clear databindings and add them again, something like:

cl.val += "11";

foreach (Control c in this.Controls)
{
       if (c is TextBox)
       {
            c.DataBindings.Clear();
            c.DataBindings.Add("Text", cl, "val", false, DataSourceUpdateMode.OnPropertyChanged);

        }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM