1
votes

I'm new to WPF and am having problems binding data to a simple ListBox. I've set it up in MainWindow.XAML

<ListBox Name="lbxShows" />

then in the code behind, I set the ItemsSource property to be an ObservableCollection of Show objects called ShowList. This is actually a property of another class (Oasis) of which OasisInst is an instance (setup in the constructor of MainApplication).

InitializeComponent();
mainApp = new MainApplication();
lbxShows.ItemsSource = mainApp.OasisInst.ShowList;

At this point, there are no items in ShowList but later, some get added and they don't appear in the ListBox.

The code for the Oasis class implements the INotifyPropertyChanged interface and then has the textbook method that's called from the ShowList setter.

private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

PropertyChanged is my PropertyChangedEventHandler event.

When I step through in debug mode, PropertyChanged is null so it seems that nothing has subscribed to my event. Given that this would usually happen automatically through a binding (I think?), then I'm guessing the binding hasn't been setup properly.

Maybe setting the ItemsSource property alone isn't sufficient to setup the binding?

2
"code for the Oasis class implements the INotifyPropertyChanged interface" -- as long as you don't change the value of the ShowList property, this is irrelevant. If you do change the value of the ShowList property, i.e. create a whole new collection and set the property value to reference that collection, then it's not sufficient to just have implemented the interface. You need to actually bind the property to the target ItemsSource property, instead of just setting it. Typically this would be done in XAML, though you can also do it in code-behind if you insist. - Peter Duniho
Your question is not answerable is-is, because without a good minimal reproducible example it's not possible to know exactly why the code doesn't work. Please fix your question. - Peter Duniho

2 Answers

0
votes

What you are doing should be enough to bind the ObservableCollection and have the U/I receive updates. I thought it was not so was going to suggest using a BindingObject but found it works. (So I too learned something). Here is a simple example that should work with the Xaml you provided. It adds an entry in the list once per second.

I am confused where you mention "PropertyChanged is my PropertyChangedEventHandler event." Note that the only PropertyChangedEventHandler required is inside the Oasis object.

Perhaps you mean you have other controls on your U/I that need a PropertyChangedEventHandler on your MainWindow but that should have no interaction with the PropertyChangedEventHandler inside the Oasis object.

---- code below ----

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Threading;

namespace ListBoxTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 

    public class OasisInstance : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        ObservableCollection<string> _items = new ObservableCollection<string>();
        public ObservableCollection<string> ShowList
        {
            get { return _items; }
            set {
                if (_items != value)
                {
                    _items = value; NotifyPropertyChanged();
                }
            }
        }

        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class MainApplication
    {
        public OasisInstance OasisInst  = new OasisInstance();
    }

    public partial class MainWindow : Window
    {
        MainApplication mainApp = new MainApplication();
        DispatcherTimer timer = new DispatcherTimer();

        public MainWindow()
        {
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += (s, e) => { mainApp.OasisInst.ShowList.Add(DateTime.Now.ToString()); };
            timer.Start();

            InitializeComponent();

            lbxShows.ItemsSource = mainApp.OasisInst.ShowList;
        }
    }
}
1
votes

All you need in the mainApp for ShowList is

public ObservableCollection<string> ShowList {get; set;}

You MUST have the getters and setters` for it to work.