Search code examples
c#wpflistboxobservablecollection

WPF Listbox not populated with items from ObservableCollection


The main-window is listening for plugging in/out USB-devices. If it is an usb-key/disk it collects a file-list from that device and show that list in a second window.

While debugging I can see that the NewUsbFiles observablecollection get's populated with 117 items. I see that the property UsbFile (before calling the showdialog) has 117 items, but nevertheless the listbox is empty.

Any thoughts ?

The method to populate / create that second window:

NewUsbFiles = new ObservableCollection<UsbFile>();
UpdateNewUsbFiles(driveName);

Application.Current.Dispatcher.Invoke(delegate
{
   var usbFileSelector = new UsbFileSelector()
   {
       Owner = this,
       UsbFiles = NewUsbFiles
    };
    usbFileSelector.ShowDialog();
});

The UsbFile-class:

 public class UsbFile 
    {
        public string UsbFileName { get; set; }
        public string OnTableFileName { get; set; }
        public bool Ignored { get; set; } = false;

        public UsbFile(string fileName)
        {
            var fileInfo = new FileInfo(fileName);
            UsbFileName = fileInfo.FullName;
            OnTableFileName = $"{fileInfo.CreationTime:yyMMddHHmmsss}_{fileInfo.Name}";
        }
    }

The XAML of the second window :

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:MainWindow="clr-namespace:PartyPictures.WPF.MainWindow" x:Name="wUsbFileSelector"
    x:Class="PartyPictures.WPF.UsbFileSelector"
        mc:Ignorable="d"
        Title="USB" HorizontalAlignment="Center" VerticalAlignment="Center" WindowStyle="ToolWindow" ScrollViewer.VerticalScrollBarVisibility="Auto" SizeToContent="WidthAndHeight">
    <StackPanel x:Name="spUsbFileList">
        <ListBox  x:Name="ImageListbox"
                  DataContext="{Binding ElementName=wUsbFileSelector}"
                 ItemsSource="{Binding UsbFiles}" 
                 Background="AliceBlue" ScrollViewer.HorizontalScrollBarVisibility="Disabled" MinWidth="200" MinHeight="200">
        </ListBox>
    </StackPanel>
</Window>

The code-behind of the second window :

public partial class UsbFileSelector : Window
    {
        public ObservableCollection<UsbFile> UsbFiles { get; set; } = new ObservableCollection<UsbFile>();

        public UsbFileSelector()
        {
            InitializeComponent();
        }
    }

Solution

  • Inside the window you can see InitializeComponent method. It creates all of the stuff defined in XAML and applies all bindings. After binding has been appplied with your empty collecton (that you have created with default property value) the binding will not know about any change of that property, that was the right answer.

    But implementing INotifyPropertyChanged is more about viewmodel instances, not visual.

    I really suggest you use Dependency Property for windows and controls if you want to bind. There are some reasons for that:

    1. Dependency property setter has built-in notify mechanism.
    2. If you bind one DP to another DP, value is shared in between.
    3. After all, it is WPF approach =)

    Here is how your window will look like after change

        public partial class UsbFileSelector : Window
        {
            public static readonly DependencyProperty UsbFilesProperty = 
                DependencyProperty.Register("UsbFiles", typeof(ObservableCollection<UsbFile>), typeof(UsbFileSelector));
    
            public ObservableCollection<UsbFile> UsbFiles 
            {
                get { return (ObservableCollection<UsbFile>) GetValue(UsbFilesProperty); }
                set { SetValue(UsbFilesProperty, value); }
            }
    
            public UsbFileSelector()
            {
                InitializeComponent();
            }
        }
    

    Also I strongly recommend you to use some WPF inspector tool while developing for the WPF, for example, snoop. You can navigate through the controls and properties while app is running and find issues much quickly you can from the code or from stackoverflow =)