Two ways DataBinding in Winforms

I am looking into data binding, I have a class with one property, then I have another class with combobox and 2 values ​​"1 and 2", I created an array object of my class with a property, so when the combobox has 1, my textbox will give it value to class [0] .property, instead, if I have 2, it will happen class [1] .property, here is the code for you to understand better:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApplication1
{
    struct Class1
    {
        public string pollo { get; set; }
    }
}

      

My second class:

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

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Class1[] prova = new Class1[2];
        int a;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            a = Convert.ToInt32(comboBox1.SelectedItem) - 1;
            prova[a].pollo = textBox1.Text;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            a = Convert.ToInt32(comboBox1.SelectedItem) - 1;
            textBox1.DataBindings.Add("Text", prova[a], "pollo", false, DataSourceUpdateMode.OnPropertyChanged);
            textBox1.DataBindings.Clear();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 0;
        }
    }
}

      

Everything works fine, but this is one way data binding. In fact, I have to set the property with a click button, in which case there is no such difference between:

textBox1.DataBindings.Add("Text", prova[a], "pollo", false, DataSourceUpdateMode.OnPropertyChanged);

      

and

textBox1 = prova[a];

      

So why use data binding? I mean, how can I do this in two ways to set my property automatically?

thank

+3


source to share


1 answer


You have some problem in your code that prevents the binding from working properly and thus hides its usefulness.

First, to be clear: the binding that is being set is between the currently selected object Class1

and the property Text

TextBox

. You use ComboBox

to change the currently selected object for binding TextBox

. I assume you are aware of this, but I want to be sure.

Now, how much trouble in the go & hellip;

  • The biggest problem is that your datatype is being Class1

    declared as struct

    , not as class

    . A type struct

    is a value type , which means that when code needs an object reference, a copy of the value is boxed (stored in the instance object

    ). It is very important to understand that this value in the box is a copy. It is completely detached from the value you stored in your array, so even if the binding was successfully set, changes to the object will not be reflected elsewhere in the code where you retrieve the object's value from the array.

  • It's almost as serious that you clear the binding immediately after setting it. This completely negates the binding data binding, allowing the framework to automatically update property values ​​based on changes in another object. So yes, in your example code, there is literally no difference between a set-binding-then-clear-binding operation and just setting the property directly.

Either of these two problems is sufficient to prevent data binding from being useful. But there is also a third problem & hellip;

  1. The type Class1

    does not implement a property changed event. In Winforms, you can implement either a named event polloChanged

    (i.e., a property name followed by a word Changed

    is spelled and capitalized literally the same) or by implementing an interface INotifyPropertyChanged

    . Without either of these mechanisms, two-way data binding cannot work because the struct has no way of knowing when the property value changed. (Ironically, what works is the binding of target-to-source and hellip, i.e. since the class TextBox

    implements the event TextChanged

    , the data binding can set the source property when the target property changes. It doesn't go the other way).

Here is a version of your code that makes full use of data binding, implementing Class1

correctly (both actual class

and with the required event polloChanged

), setting up the binding correctly, and binding the object pollo

in Label

to clear the object property pollo

:



class Class1
{
    private string _pollo = "";
    public string pollo
    {
        get { return _pollo; }
        set
        {
            _pollo = value;
            Raise(polloChanged, this);
        }
    }

    private static void Raise(EventHandler handler, object sender)
    {
        if (handler != null)
        {
            handler(sender, EventArgs.Empty);
        }
    }

    public event EventHandler polloChanged;
}

      


public partial class Form1 : Form
{
    private Class1[] _prova =
    {
        new Class1 { pollo = "<not set 1>" },
        new Class1 { pollo = "<not set 2>" }
    };

    public Form1()
    {
        InitializeComponent();

        comboBox1.SelectedIndex = 0;
    }

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Obviously in a more complicated data binding scenario, you might
        // want to be more specific about which binding(s) is(are) being
        // removed, rather than just clearing everything.
        textBox1.DataBindings.Clear();
        label1.DataBindings.Clear();

        // If the user edits the text in the TextBox, the pollo property
        // of the currently-selected object will be immediately updated
        textBox1.DataBindings.Add("Text", _prova[comboBox1.SelectedIndex],
            "pollo", false, DataSourceUpdateMode.OnPropertyChanged);

        // We're never going to change the label1.Text property directly,
        // so the binding doesn't ever need to update the source property.
        label1.DataBindings.Add("Text", _prova[comboBox1.SelectedIndex],
            "pollo", false, DataSourceUpdateMode.Never);
    }
}

      

I am assuming that you can output the required formats textBox1

, comboBox1

and label1

in the form, instead of allowing me to place all the constructor code.


Finally, if you prefer the approach INotifyPropertyChanged

, here's what yours Class1

would look like:

class Class1 : INotifyPropertyChanged
{
    private string _pollo = "";
    public string pollo
    {
        get { return _pollo; }
        set
        {
            _pollo = value;
            OnPropertyChanged();
        }
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

      

+4


source







All Articles