tags:

views:

654

answers:

3

I'm self-learning C#, OOP, and WPF so the potential for stuff ups is staggering.

So given that, can someone please explain why after clicking the button in my tiny test example the Name property appears in the TextBox but the ListBox shows nothing?

XAML:

<Window x:Class="BindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BindingTest" Height="250" Width="300">
<Grid Name="mainGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="50" />
        <RowDefinition Height="100" />
    </Grid.RowDefinitions>
    <Button 
            Grid.Row="0"
            Name="MakeIntListButton"
            Click="MakeIntListButton_Click">Make and Display Integer List</Button>
    <TextBox Grid.Row="1" Text ="{Binding Path=Name}"
             />
    <ListBox
        Grid.Row="2"
        ItemsSource="{Binding Path=MyIntegers}"
        />
</Grid>

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BindingTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void MakeIntListButton_Click(object sender, RoutedEventArgs e)
        {
            AClass InstanceOfAClass = new AClass();
            InstanceOfAClass.MyIntegers.Add(6);
            InstanceOfAClass.MyIntegers.Add(7);
            InstanceOfAClass.MyIntegers.Add(42);

            InstanceOfAClass.Name = "Fred";


            mainGrid.DataContext =InstanceOfAClass ;
        }
    }

    public class AClass
    {
        public string Name {get;set;}
        public List<int> MyIntegers = new List<int>();
    }
}
+2  A: 

Part of me wonders whether it's something to do with the fact that "MyIntegers" is a public field rather than a property. Can you refactor you class to look like this and try it?

public class AClass
{
    private List<int> _ints = new List<int>();

    public string Name { get; set; }
    public List<int> MyIntegers
    {
        get { return _ints; }
    }
}
Matt Hamilton
Thanks Matt. That had me stumped for hours.
David Smith
We've both learned something then! I had no idea that WPF wouldn't bind to public fields like that. I'll have to read up on that!
Matt Hamilton
A: 

I ran your sample and when I clicked on the button the TextBox was populated with the Name as expected.

The only problem I encountered was that the ListView was not getting populated with the list of integers. That's to do with the fact that XAML is not very comfortable with generics if you modify it to bind to an array instead it works. WPF supports consumption of XAML fine, it's using generics within XAML that's not supported. As Matt Hamilton points out in his answer MyIntegers just needs to be made a propety by adding a get acessor.

Add C# Property:

public int[] MyInts { get { return MyIntegers.ToArray(); } }

XAML:

<ListBox Grid.Row="2" ItemsSource="{Binding Path=MyInts}" />
sipwiz
XAML and data binding work fine with generics -- ObservableCollection<T> is the cornerstone of list binding in WPF! There is absolutely no need to convert a generic collection to an array in order to bind to it.
itowlson
Yes you are right. I got mixed up between generics support directly in XAML (http://blogs.msdn.com/mikehillberg/archive/2006/10/06/LimitedGenericsSupportInXaml.aspx) as opposed to consuming it.
sipwiz
Thanks sipwiz it did work, but probably because we are now binding to a property not a field.
David Smith
A: 

Look into using the System.Collections.ObjectModel.ObservableCollection for list binding instead of a plain List.

Nathan