28

Say I have a global variable INT named X. Since X is global, we can assume that anything can modify its value so it is being changed everytime.

Say I have a Label control named "label". Here's what I want to accomplish:

I want to "bind" the value of label.Text to variable X. In such a way that when variable X is changed, it will be reflected back to label.Text.

Now, I don't want to write event listeners and play with delegates with this one (I want the least amount of code as possible). Is there a way to use the DataBinding component for this one? or any other novel techniques?

MartyIX
  • 27,828
  • 29
  • 136
  • 207
Ian
  • 5,625
  • 11
  • 57
  • 93

4 Answers4

37

If you want to use the Databinding infrastructure, and reflect the changes made to a value, you need a way to notify the UI about the changes made to the binding value.

So the best way to do that is to use a property and implement the INotifyPropertyChanged interface, like this:

class frmFoo : Form, INotifyPropertyChanged
{        
    private string _foo;

    public string Foo
    {
        get { return _foo; }
        set
        {
            _foo = value;
            OnPropertyChanged("Foo");
        }
    }

    protected virtual void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

Also remember that you need to setup the binding on the label first:

public frmFoo()
{
    InitializeComponent();
    lblTest.DataBindings.Add(new Binding("Text", this, "Foo"));
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
Iñaki Elcoro
  • 2,153
  • 1
  • 18
  • 33
  • 2
    I think this answer is exactly what Ian needs. Maybe it's even better to create a copy of PropertyChanged before checking against null, otherwise it might change to null right before being called, like this: protected virtual void OnPropertyChanged(string property) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(property)); } } (see http://stackoverflow.com/questions/672638/use-of-null-check-in-event-handler/672666#672666 for details) – Simon D. Jun 30 '10 at 07:43
  • I agree, that's better reference implementation of the PropertyChanged pattern, with support for multithreaded scenarios. – Iñaki Elcoro Jun 30 '10 at 08:50
10

For a multi-threaded program (so almost every windows forms program) iCe's answer is not a good one, because it won't let you change the label anyway (you will get some cross-threading error). The simplest way to fix the problem is creating property in setter:

private string _labelText;
public string labelText
{
    get { return _labelText; }
    set
    {
        _labelText = value;
        updateLabelText(_labelText); //setting label to value
   }
}

where updateLabelText(string) is thread safe:

delegate void updateLabelTextDelegate(string newText);
private void updateLabelText(string newText)
{
     if (label1.InvokeRequired)
     {
          // this is worker thread
          updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
          label1.Invoke(del, new object[] { newText });
     }
     else
     {
          // this is UI thread
          label1.Text = newText;
     }
}
Piotr Dabkowski
  • 5,661
  • 5
  • 38
  • 47
Maciej Oziębły
  • 1,769
  • 15
  • 14
4

I don't think you'd be able to bind to a public variable. A variable by itself doesn't have the ability to notify listeners of a change in its value.

That is why you need to wrap the variable in a property. In the setter you raise an event to notify the UI controls that are bound to it, so that they can refresh and display the new value. The framework has a mechanism for this - INotifyPropertyChanged - try this link for a how-to.

Gishu
  • 134,492
  • 47
  • 225
  • 308
1

Create a property for X. In setter update the label.Text property.

private int _x;
public int X {
    get 
    { 
        return _x; 
    } 
    set 
    { 
        _x = value;
        label.Text = _x.ToString();
    }
}
Krunal
  • 3,443
  • 3
  • 23
  • 27
  • 2
    Wrong, if you do that from a thread that is not the UI thread you will trigger a Cross-Thread Operation not valid exception – Pic Mickael Oct 10 '13 at 15:16