Search code examples
c#wpfdatagrid

WPF - DataGrid doesn't show list


My goal is to output a list in a datagrid, but this doesn't work and the datagrid is empty.

I tried to display the list in an other way and it did (but I can't remember what it was) and it worked, except for it not being in a datagrid but just data. I have changed up some things, but back then it reached the end and got displayed.

ViewModel in Mainwindow:

public class ViewModel
        {
            public List<ssearch> Items { get; set; }

            private static ViewModel _instance = new ViewModel();
            public static ViewModel Instance { get { return _instance; } }
        }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();

            //For simplicity, let's say this window opens right away
            var Mdata = new MDataWindow { DataContext = DataContext };
            Mdata.Show();
        }

Other Window for data display:

string searchParam = "status = 1"; 
        public MDataWindow()
        {
            InitializeComponent();
        }

        private void AButton_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.ViewModel.Instance.Items = Search(searchParam);
        }

public List<ssearch> Search(string where)
        {
            {
                 //Lots of stuff going on here
            }
            return returnList;
        }

And in WPF:

<Window x:Class="WPFClient.MDataWindow"
        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:local="clr-namespace:WPFClient"
        mc:Ignorable="d"
        Title="MDataWindow" Height="Auto" Width="Auto">
    <StackPanel>
        <Button x:Name="AButton" Click="AButton_Click" Content="Load" />

        <DataGrid ItemsSource="{Binding Items}" />
    </StackPanel>
</Window>

I have no clue where the error is and tried to strip the code down as much as possible without killing error sources. The Datagrid just stays empty when I press the "Load" button.

EDIT: I tried to convert the list into an observableColletion before passing it to the ViewModel, but this didn't work. I am working with a library, which I am not sure how to use observableCollection with, so I converted it instead of using it right away:

VM: public ObservableCollection<Product> Items { get; set; }

Data Window:

List<Product> pp = Search_Products(searchParam);
var oc = new ObservableCollection<Product>(pp);
MainWindow.ViewModel.Instance.Items = oc;

Solution

  • The ViewModel class should implement the INotifyPropertyChanged interface and raise its PropertyChanged event whenever Items is set to a new collection:

    public class ViewModel : INotifyPropertyChanged
    {
        private List<ssearch> _items;
        public List<ssearch> Items
        {
            get { return _items; }
            set { _items = value; OnPropertyChanged(); }
        }
    
        private static ViewModel _instance = new ViewModel();
        public static ViewModel Instance { get { return _instance; } }
    
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    This is required to notify the view regardless of the type of Items.

    If you change the type of Items to ObservableCollection<T>, you should initialize the collection in the view model once:

    public class ViewModel
    {
        public ObservableCollection<ssearch> Items { get; } = new ObservableCollection<ssearch>();
    
        private static ViewModel _instance = new ViewModel();
        public static ViewModel Instance { get { return _instance; } }
    }
    

    ...and then add items to this collection instead of setting the property to a new one:

    private void AButton_Click(object sender, RoutedEventArgs e)
    {
        MainWindow.ViewModel.Instance.Items.Clear();
        var search = Search(searchParam);
        if (search != null)
            foreach (var x in search)
                MainWindow.ViewModel.Instance.Items.Add(x);
    
    }