views:

211

answers:

3

Hi. I need TextBox which will reflect changes in databound string. I tried following code:

public partial class Form1 : Form
{
    string m_sFirstName = "Brad";
    public string FirstName
    {
        get { return m_sFirstName; }
        set { m_sFirstName = value; }
    }

    public Form1()
    {
        InitializeComponent();

        textBox1.DataBindings.Add("Text", this, "FirstName");
    }

    private void buttonRename_Click(object sender, EventArgs e)
    {
        MessageBox.Show("before: " + FirstName);
        FirstName = "John";
        MessageBox.Show("after: " + FirstName);
    }
}

After launching an application, textBox1 is correctly filled with Brad. I clicked the Button, it renamed FirstName to "John" (second messagebox confirms it). But the textBox1 is still filled with Brad, not with John. Why? What will make this work?

A: 

You need to perform databinding again upon button click, else it only run once upon form instantiation.

To add: above statement wasn't the right one for the requirement. It still work (see code below), but defeats the purpose of binding via event handling.

Binding binding1; //binding instance
public Form1()
{
    InitializeComponent();
    binding1 = textBox1.DataBindings.Add("Text", this, "FirstName"); //assign binding instance
}

private void buttonRename_Click(object sender, EventArgs e)
{
    MessageBox.Show("before: " + FirstName);
    FirstName = "John";
    textBox1.DataBindings.Remove(binding1); //remove binding instance
    binding1 = textBox1.DataBindings.Add("Text", this, "FirstName"); //add new binding
    MessageBox.Show("after: " + FirstName);
}
o.k.w
I got textBox in my example, but there is also databinding to readonly controls (listbox, label,...) . Is really "label1.DataBindings.Add("Text", this, "FirstName");" the same as "label1.Text = FirstName;" ??? I still believe there must exist double-side binding.
jing
@Jing, my answer wasn't the appropriate one for your need. For mine to work, need to remove the databinding instance before adding another one. The other answers gave you better designs.
o.k.w
+2  A: 

One way is to add a FirstNameChanged event which data binding will then hook into. Then raise the event when you've changed the property, and it will rebind. For example:

using System;
using System.Drawing;
using System.Windows.Forms;

public class DataBindingTest : Form
{
    public event EventHandler FirstNameChanged;

    string m_sFirstName = "Brad";
    public string FirstName
    {
        get { return m_sFirstName; }
        set 
        { 
            m_sFirstName = value;
            EventHandler handler = FirstNameChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

    public DataBindingTest()
    {
        Size = new Size(100, 100);
        TextBox textBox = new TextBox();
        textBox.DataBindings.Add("Text", this, "FirstName");

        Button button = new Button
        { 
            Text = "Rename",
            Location = new Point(10, 30)
        };
        button.Click += delegate { FirstName = "John"; };
        Controls.Add(textBox);
        Controls.Add(button);
    }

    static void Main()
    {
        Application.Run(new DataBindingTest());
    }
}

There may well be other ways of doing it (e.g. using INotifyPropertyChanged) - I'm not a databinding expert by any means.

Jon Skeet
+2  A: 

The reason why the DataBinding is not reflecting your changes is because you are binding a simple System.String object which have not been designed to throw events when modified.

So you have 2 choices. One is to rebind the value when in the Click event of your button (please avoid!). The other is to make a custom class that will implement INotifyPropertyChanged like this:

public partial class Form1 : Form
{
    public Person TheBoss { get; set; }

    public Form1()
    {
        InitializeComponent();

        TheBoss = new Person { FirstName = "John" };

        textBox1.DataBindings.Add("Text", this, "TheBoss.FirstName");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        TheBoss.FirstName = "Mike";
    }


    public class Person : INotifyPropertyChanged
    {
        private string firstName;

        public string FirstName
        {
            get 
            { 
                return firstName; 
            }
            set 
            { 
                firstName = value;
                NotifyPropertyChanged("FirstName");
            }
        }

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

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

INotifyPropertyChanged documentation : MSDN

Ucodia