Binding label to a variable

15,333

Solution 1

Your code will work if you change your class to this...

  public partial class Window1 : Window, INotifyPropertyChanged
    {
        private int _idCounter;
        public int IdCounter
        {
            get { return _idCounter; }
            set
            {
                if (value != _idCounter)
                {
                    _idCounter = value;
                    OnPropertyChanged("IdCounter");
                }
            }
        }
        public Window1()
        {
            InitializeComponent();
            myLabel.SetBinding(ContentProperty, new Binding("IdCounter"));
            DataContext = this;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            IdCounter++;
        }
        #region INotifyPropertyChanged Implementation
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string name)
        {
            var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion
    }

Some of the issues you were having are...

The window itself should implement INotifyPropertyChanged so that the binding engine can place an ear on it.

the IdCounter needs to be public and have a public getter on it so that the binding engine can 'get' it.

You should set the DataContext to whatever class has declared IdCounter (the MainWindow in this case). Part of the problem was that the binding engine had no DataContext.

The BindingMode setting was a red-herring since a Label binds that way by default.

The UpdateSourceTrigger was a red-herring since the content of the label does not have a mechanism to update the source property. A label's content is not like a text box where the user can type something that the code needs to know about. When you're binding to something that the user cannot change, forget about UpdateSourceTrigger, it's the Target property that counts.

The handler should mark the event. This is good practice and did not affect the binding.

The binding constructor needs only the path.

This code will give you your expected result; i.e., that the label updates when the button is clicked. Checked, compiled, and executed on vs2013, .net 4.5.

The other respondents said you should use a View Model. I agree with this 100%, and overall it's a good thing to consider.

Solution 2

You want to use a property to do this, as well as implementing INotifyPropertyChanged so that the label's content gets updated when the property changes.

Here's an example using a simple ViewModel

xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:converters="clr-namespace:WpfApplication1"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Width="200" Height="50" Content="{Binding MyLabel}"/>
        <Button Height="30" Width="100" Content="Increment" Click="Button_Click" />
    </StackPanel>
</Window>

xaml.cs:

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        MainViewModel vm = new MainViewModel();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            vm.MyLabel += 1;
        }
    }
}

MainViewModel.cs:

namespace WpfApplication1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Members
        private int _myLabel;
        #endregion Members

        #region Properties
        public int MyLabel
        {
            get
            {
                return _myLabel;
            }
            set
            {
                _myLabel = value;
                NotifyPropertyChanged("MyLabel");
            }
        }

        #endregion Properties

        public MainViewModel()
        {
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

Note: Ideally, you would want to use a Command for the Button instead of a Click event handler

Solution 3

  1. You cannot bind to something that is private or a field so convert it into public property. You can find more as to what is a valid binding source here
  2. If you want changes to your property be picked up by UI you should implement INotifyPropertyChanged interface and raise event each time value of the property changes. So idCounter should look more like this:

    private int _idCounter;
    
    public int idCounter
    {
        get { return _idCounter; }
        set
        {
            if (_idCounter != value)
            {
                _idCounter = value;
                OnPropertyChanged("idCounter");
            }
        }
    }
    
  3. When you create binding to property you use Path

  4. Binding works in binding context so you need to specify from where to take this Path. Easiest way to do that is to set DataContext. So in your case initialization should look more like this:

    Binding b = new Binding("idCounter");
    b.Mode = BindingMode.OneWay;
    b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    
    myLabel.SetBinding(Label.ContentProperty, b);
    DataContext = this;
    
  5. As @d.moncada suggested in his answer you should create dedicated view model

Share:
15,333
Safiron
Author by

Safiron

Updated on June 25, 2022

Comments

  • Safiron
    Safiron almost 2 years

    I am just starting with WPF and I am trying to setup binding between a local variable and a label. Basicaly I want to update the label when local variable changes. I was searching for solution but they all just use textbox as a source not just class variable and I am not even sure it works this way. So here is my code.

    public partial class MainWindow : Window
    {
        int idCounter;
    
        public MainWindow()
        {
            InitializeComponent();
    
    
            Binding b = new Binding();
            b.Source = idCounter;
            b.Mode = BindingMode.OneWay;
            b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    
            myLabel.SetBinding(Label.ContentProperty,b);
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            idCounter++;
        }
    }
    

    Button does work, idCounter changes value, but it does not update in label so I guess binding is wrong. Can someone tell me what is wrong? Thanks

  • Johnathon Sullinger
    Johnathon Sullinger almost 10 years
    Technically your objects don't inherit from INotifyPropertyChange, they implement it. Nice answer though.
  • Gayot Fow
    Gayot Fow almost 10 years
    @JohnathonSullinger, thanks for the astute head's up. I'll edit. TA