1

I came from a Linux heavy environment, where I wrote most of my tools in Python but now I am in a windows heavy environment, and need to share my tools with my team and some need to be GUI driven so I am trying to learn C#/WPF. I'm getting confused on Data Binding to an ObservableCollection in the code behind. I can get it work, but I don't understand why, which bothers me.

My code is simple, and I am literally just trying to get the basics working so I can move on to more complicated parts:

XAML:

<ListView x:Name="lvUrlList" HorizontalAlignment="Left" Height="441" Margin="15,62,0,0" VerticalAlignment="Top" Width="486" SelectionChanged="listView_SelectionChanged" ItemsSource="{Binding Path=urlList, ElementName=MainWindow1}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <WrapPanel>
                    <TextBlock Text="{Binding domain}"/>
                </WrapPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

Code Behind:

namespace ReferalScraper
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        //public ObservableCollection<Url> urlList { get; set; } // Method 1
        public ObservableCollection<Url> urlList = new ObservableCollection<Url>(); // Method 2
        public MainWindow()
        {
            // urlList = new ObservableCollection<Url>(); // Method 1
            InitializeComponent();
            urlList.Add(new Url() { domain = "www.test1.com" });

        }

        public class Url
        {
            public string domain { get; set; }

        }

        private void button_Click(object sender, RoutedEventArgs e)
        {

            urlList.Add(new Url() { domain = "www.test2.com" });
            urlList.Add(new Url() { domain = "www.test3.com" });

        }
    }
}

The uncommented method for creating and instantiating the ObservableCollection doesn't work, the code compiles but I get the output error:

System.Windows.Data Error: 40 : BindingExpression path error: 'urlList' property not found on 'object' ''MainWindow' (Name='MainWindow1')'. BindingExpression:Path=urlList; DataItem='MainWindow' (Name='MainWindow1'); target element is 'ListView' (Name='lvUrlList'); target property is 'ItemsSource' (type 'IEnumerable')

Which I understand that it means it can't find the urlList object in MainWindow. But I don't understand why it can't find it.

If I switch to the Method 1 and uncomment the following two lines (and comment out the "Method 2" part) it works fine:

public ObservableCollection<Url> urlList { get; set; }
...
public MainWindow(){
       urlList = new ObservableCollection<Url>()

Why is declaring the ObserverableCollection with the { get; set } needed? I don't quite grasp why I can't just instantiate my ObservableCollection as an empty ObserverableCollection like I am in Method 2.

I'm feeling incredibly dense, and haven't quite been able to track down the right terminology to even get close to answering my questions. Can anyone explain to a not so bright fellow what I am missing?

I have a feeling this is some C# understanding that I am missing.

z0dSki
  • 35
  • 1
  • 4

2 Answers2

4

The { get; set; } syntax defines your uriList as a property (an auto-implemented property, in this case ). Without this, uriList is simply a field.

WPF Data Binding cannot bind to fields. See this related question for some further discussion as to why this is the case.

Generally in C# fields are not usually exposed as public, properties are preferred. This allows you to change the get/set implementation if required. As an aside, the naming convention for properties is PascalCased (so UriList rather than uriList).

Community
  • 1
  • 1
Charles Mager
  • 25,735
  • 2
  • 35
  • 45
  • Thank you, I will take this and do more reading on Fields v. Properties, I have a feeling that is where I am missing some knowledge. Can I define and instantiate the property all at once? Is there a reason I need to later call the `new ObserverableCollection` part? – z0dSki Jan 16 '16 at 18:22
  • See the link to auto-implemented properties. If you are using C# 6 (if you are running VS 2015, you will be) then you can do this in one line similarly to field initialisation. You could also omit the `set`. – Charles Mager Jan 16 '16 at 18:25
  • Oh boy, I was being **extremely** dense, and it just dawned on me. MainWindow is the class I am exposing the property on, so of course there is nothing there if nothing is exposed! That was a massive duh moment. Thank you again, the resources clarified it and I have some good reading to do. – z0dSki Jan 16 '16 at 19:04
0

You use ElementName binding when you try to get the Property you are binding, from another FramworkElement's property, which isn't the case here,

you need to first: properly set the DataContext either from the codebehind in the MainWindow constructor:

this.DataContext=this;

or from the Xaml in the Window

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Then declare you UriList as a Property so it can be used with binding

 private ObservableCollection<Url> _uriList = new ObservableCollection<Url()
    {
        new Url() { domain = "www.test2.com" }
    };

    public bool UrlList
    {
        get
        {
            return _uriList;
        }

        set
        {
            if (_uriList == value)
            {
                return;
            }

            _uriList = value;

        }
    }

and change your binding to the following :

ItemsSource="{Binding UrlList}
SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47