Jesse Carter
Jesse Carter

Reputation: 21147

databinding to changing element property

I'm working on a small WPF application in which I have a combobox that is bound to an ObservableCollection in the code behind:

public Molecule CurrentMolecule { get; set; }
public ObservableCollection<string> Formulas { get; set; }

public MainWindow()
{
     CurrentMolecule = new Molecule();
     Formulas = new ObservableCollection<string>(CurrentMolecule.FormulasList.ToList());
     DataContext = this;

     InitializeComponent();
}

<ComboBox x:Name="cmbFormula" ItemsSource="{Binding Path=Formulas}" SelectionChanged="cmbFormula_SelectionChanged"/>

This works fine to populate my combo box with the CurrentMolecule.FormulasList however if at some point I set CurrentMolecule to a new instance of Molecule the databinding no longer works. Do I need to implement some kind of OnPropertyChanged event so that no matter what the contents of the combo box will stay current with the CurrentMolecule.FormulasList?

Upvotes: 0

Views: 76

Answers (2)

Anand Murali
Anand Murali

Reputation: 4109

You have to implement INotifyPropertyChanged, only then the changes will be updated in UI.

Here are the modifications that I've done to your code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private Molecule _CurrentMolecule;

        public Molecule CurrentMolecule
        {
            get
            {
                return _CurrentMolecule;
            }
            set
            {
                _CurrentMolecule = value;
                OnPropertyChanged("CurrentMolecule");
                Formulas =  new ObservableCollection<string>(CurrentMolecule.FormulasList.ToList());
            }
        }

        private ObservableCollection<string> _Formulas;

        public ObservableCollection<string> Formulas
        {
            get { return _Formulas; }
            set
            {
                _Formulas = value;
                OnPropertyChanged("Formulas");
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            CurrentMolecule = new Molecule();
            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Edit: A better approach is to create a ViewModel and then bind it to the DataContext of the Window.

Define a new class called ViewModel as below. Note you might want to change the namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace WpfApplication1
{
    public class ViewModel : INotifyPropertyChanged
    {
        #region Properties
        private Molecule _CurrentMolecule;
        public Molecule CurrentMolecule
        {
            get
            {
                return _CurrentMolecule;
            }
            set
            {
                _CurrentMolecule = value;
                OnPropertyChanged("CurrentMolecule");
                Formulas = new ObservableCollection<string>(CurrentMolecule.FormulasList.ToList());
            }
        }

        private ObservableCollection<string> _Formulas;
        public ObservableCollection<string> Formulas
        {
            get { return _Formulas; }
            set
            {
                _Formulas = value;
                OnPropertyChanged("Formulas");
            }
        }
        #endregion

        #region Constructor
        public ViewModel()
        {
            CurrentMolecule = new Molecule();
        }
        #endregion

        #region INotifyPropertyChanged implementation
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

Modify the MainWindow code behind file as below

public MainWindow()
{
    InitializeComponent();

    DataContext = new ViewModel();
} 

Upvotes: 2

VidasV
VidasV

Reputation: 4895

You are probably missing WPF controls datacontext fundamentals. If you are using binding like {Binding CurrentMolecule.FormulasList} or parent controls datacontext is bound to "CurrentMolecule" whenever you swap DataContext of that item, the binding will reset. If you would like to keep the datacontext bound to the FormulasList even when the parent datacontext changes. You need to bind that context directly to FormulasList property and make sure that other parent controls are not using CurrentMolecule as a datacontext, even when its instance changes in your ViewModel.

Upvotes: 0

Related Questions