Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't get WPF ListView to bind to ObservableCollection

Tags:

wpf

I've been playing around with WPF for the first time, specifically using a ListView that I want to bind to a ObservableCollection that is a property on the code-behind page. Right now I'm just trying to get a feel for how things work so I've tried keeping this simple. Unfortunately I don't quite see where I'm going wrong with this.

My code-behind page has a property that looks like this:

public ObservableCollection<Code> Code { get; set; }

I have a button on the form that queries and populates the Code property.

The Code class is a simple POCO class:

public class Code
{
   public string Line { get; set; }
}

I have added a namespace to the XAML window:

<Window x:Class="SampleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"       
        xmlns:local="clr-namespace:SampleWPF" 
        Title="MainWindow" Height="350" Width="525"                
        >

And the ListView looks like this:

<DockPanel Height="311" HorizontalAlignment="Left" Name="dockPanel1" 
           VerticalAlignment="Top" Width="182">
    <ListView Name="lstCode"                        
              ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window, AncestorLevel=1}, Path=Code}"
              DisplayMemberPath="Line">

        <ListView.View>
            <GridView>
                <GridViewColumn DisplayMemberBinding="{Binding Line}" />
            </GridView>
        </ListView.View>
    </ListView>
</DockPanel>

I have also attempted to set the DataContext in the code behind contructor, with no luck, ex.:

this.DataContext = this;

EDIT: Moving this line to after the line of code that creates the collection fixed things (along with the other changes suggested).

And I also tried to explicitly set the ItemsSource in code (in my click handler):

this.lstCode.ItemsSource = this.Code;

I've looked at a number of examples but I'm still missing something here (not really a surprise).

like image 948
Paul Avatar asked Feb 03 '11 20:02

Paul


1 Answers

Uh, you're trying to do something simple with some terrible magic ;) Your binding should look like {Binding Path=Code}. To make this work you should also set DataContext to this, just like you wrote. This should give you simplest binding. Magic with finding ancestors is not necessary in here.

In advanced applications you should rather use Model - View - ViewModel pattern and set data context to ViewModel object rather than to this, but just for testing and trying WPF out, this approach should be ok.

Here is some sample:

<Window x:Class="binding_test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ListView ItemsSource="{Binding Path=Code}" />
</Grid>

And code behind:

using System.Collections.ObjectModel;
using System.Windows;

namespace binding_test
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<int> Code { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            Code = new ObservableCollection<int>();
            Code.Add(1);
            this.DataContext = this;
        }
    }
}

And here is how you should create listview for your sample. You have special class and you probably don't want to display ToString() result on each object. To display element any way you could imagine, you should use data template and there create controls and bind them to properties of element, that was in list you've bind ListView.

    <ListView ItemsSource="{Binding Code}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Line}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
like image 120
Jarek Avatar answered Dec 06 '22 03:12

Jarek