6

I'm trying to display data in a ListView with WPF and C#, and I'm confused by the different examples and methods I have seen. I'm looking for a fully working example similar to my program, or a list of pre-requisites to make it work. I'll be happy if I manage to display just 1 row of data from my collection. Currently, the list view displays nothing.

C#:

public partial class MainWindow : Window
{
    public ObservableCollection<Row> Rows { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        Rows = new ObservableCollection<Row>();
        Rows.Add(new Row 
        {
            ID = "42",
            Category = "cat",
            CharLimit = 32,
            Text = "Bonjour"
        });
    }
}

public class Row
{
    public string ID { get; set; }
    public string Category { get; set; }
    public int CharLimit { get; set; }
    public string Text { get; set; }
}

XAML:

<ListView ItemsSource="{Binding Path=Rows}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="200" Header="ID" DisplayMemberBinding="{Binding Path=ID}" />
            <GridViewColumn Width="200" Header="Category" DisplayMemberBinding="{Binding Path=Category}" />
            <GridViewColumn Width="200" Header="Text" DisplayMemberBinding="{Binding Path=Text}" />
        </GridView>
    </ListView.View>
</ListView>

Thanks in advance

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Noxxys
  • 879
  • 1
  • 9
  • 19
  • It looks like you're not setting a DataContext anywhere, which in this case should be the instance of MainWindow. I would also recommend looking into the MVVM design pattern and an MVVM framework. – devdigital Jun 08 '13 at 21:32
  • 1
    Thanks, I'll check some MVVM tutorials to grasp the idea and try doing it right :) – Noxxys Jun 09 '13 at 12:42

2 Answers2

8

Create a viewmodel which can be set as the data context for the XAML

 public class WindowsViewModel
 {
    private ObservableCollection<RowViewModel> m_Rows;

    public ObservableCollection<RowViewModel> Rows
    {
        get { return m_Rows; }
        set { m_Rows = value; }
    }

    public WindowsViewModel()
    {
        Rows = new ObservableCollection<RowViewModel>();
        Rows.Add(new RowViewModel
            {
                ID = "42",
                Category = "cat",
                CharLimit = 32,
                Text = "Bonjour"
            });
    }
}

Implement the class RowViewModel in the below fashion:

 public class RowViewModel:INotifyPropertyChanged
    {
      public RowViewModel()
      {
      }
      private string m_ID;
      public string ID
      { 
            get
            {
                return m_ID;
            } 
            set 
            {
                m_ID = value;
                NotifyPropertyChanged("ID");
            }
      }
      public string Category
      { 
            get; 
            set; 
      }

      public int CharLimit
      { 
        get; 
        set; 
      }

      public string Text 
      { 
        get;
        set;
      }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string Obj)
    {
        if (PropertyChanged != null)
        {
            this.PropertyChanged(this,new PropertyChangedEventArgs(Obj));
        }
    }
}

In the code behind of XAML, add the code:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new WindowsViewModel();
        }
    }

Add the update source trigger property in the listview node:

<ListView ItemsSource="{Binding Rows, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="200" Header="ID" DisplayMemberBinding="{Binding Path=ID}" />
                    <GridViewColumn Width="200" Header="Category" DisplayMemberBinding="{Binding Path=Category}" />
                    <GridViewColumn Width="200" Header="Text" DisplayMemberBinding="{Binding Path=Text}" />
                </GridView>
            </ListView.View>

user45623
  • 621
  • 4
  • 18
Arushi Agrawal
  • 619
  • 3
  • 10
  • 1
    Wow thanks for the lengthy answer. I realize I lack a lot of knowledge on the topic so I'll read [this MVVM tutorial](http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial) before copy/pasting your answer. – Noxxys Jun 09 '13 at 12:49
1

You must specify source otherwise, like in your case, it will look for the property in current context which by default, if nothing else is specified, will be DataContext. Try something like this:

<ListView ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Rows}">

Like that you specify that it should look for Rows in current Window

dkozl
  • 32,814
  • 8
  • 87
  • 89
  • Thank you, adding a DataContext in the C# code was easy and made it work. I will also look into @Arushi-Agrawal 's solution as my ListView doesn't update when I change the properties of my Rows. – Noxxys Jun 09 '13 at 12:32