Question

I am new to WPF and am trying to understand how to use data binding to bind the controls on my window to objects in my code behind. I see several questions about accessing XAML objects from the codebehind, but that's not what I'm looking for. I already know how to do that.

label1.Content = LabelText;
listbox1.ItemsSource = ListItems;

I have also seen answers about how to access a class in the codebehind from XAML.

But I don't see how to apply that to a specific instance of the class. Here is an example of what I'm trying to do. The 'Bindings' are obviously incorrect. That is what I need help with.

public partial class MainWindow : Window
{
    private string _labelText;
    private List<string> _listItems = new List<string>();

    public MainWindow()
    {
        InitializeComponent();

        _labelText = "Binding";
        _listItems.Add("To");
        _listItems.Add("An");
        _listItems.Add("Object");
    }

    public string LabelText
    {
        get { return _labelText; }
        set { _labelText = value; }
    }

    public List<string> ListItems
    {
        get { return _listItems; }
        set { _listItems = value; }
    }
}

<Window x:Class="SO_Demo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SO Demo" Height="160" Width="225">
  <Grid DataContext="MainWindow">
    <Label x:Name="label1" Width="80" Height="25" Margin="12,12,0,0" 
           Content="{Binding Path=LabelText}"
           HorizontalAlignment="Left" VerticalAlignment="Top" />
    <ListBox x:Name="listbox1" Width="100" Height="60" Margin="12,44,0,0" 
             ItemsSource="{Binding Path=ListItems}" DisplayMemberPath="ListItems"
             HorizontalAlignment="Left" VerticalAlignment="Top" />
  </Grid>
</Window>   

The books and tutorials I have read make it sound like this should be very simple. What am I missing?

Was it helpful?

Solution

While you can DataBind directly to the class in the manner you're attempting, it is not how this is commonly done. The recommended approach is to create an object (ViewModel) that aggregates all the model data you want displayed in your UI, and then set that ViewModel as the DataContext of your View (Window in this case). I would recommend reading about MVVM, which is how most WPF application are built. But the example below can get you started.

Here is a simple example based on your sample above:

public class MyViewModel : INotifyPropertyChanged
{
    private string _title;
    private ObservableCollection<string> _items;

    public string LabelText
    { 
        get { return _title; } 
        set 
        { 
            _title = value;
            this.RaisePropertyChanged("Title");
        }
    }

    public ObservableCollection<string> ListItems { 
        get { return _items; }
        set 
        { 
            _items = value;   //Not the best way to populate your "items", but this is just for demonstration purposes.
            this.RaisePropertyChanged("ListItems");
        }
    }

    //Implementation of INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}

CodeBehind

public partial class MainWindow : Window
{
    private MyViewModel _viewModel;

    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new MyViewModel();

        //Initialize view model with data...

        this.DataContext = _viewModel;
    }
}

View (Window)

<Window x:Class="SO_Demo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SO Demo" Height="160" Width="225">
  <Grid>
    <Label x:Name="label1" Width="80" Height="25" Margin="12,12,0,0"               Content="{Binding Path=LabelText}"
           HorizontalAlignment="Left" VerticalAlignment="Top" />
    <ListBox x:Name="listbox1" Width="100" Height="60" Margin="12,44,0,0" 
             ItemsSource="{Binding Path=ListItems}"
             HorizontalAlignment="Left" VerticalAlignment="Top" />
  </Grid>
</Window>

OTHER TIPS

Your issue is you're saying Grid DataContext = MainWindow, you don't need to do that (datacontexts are inherited by children except in cases where they provide their own override for that) and you're doing it wrong (you're setting the context to the STRING MainWindow, and a STRING doesn't have a "ListItems" or "LabelText" Property.

If you want to use the current class as your datacontext then in the constructor of your MainWindow just do

this.DataContext = this;

And remove the datacontext you placed on the grid in XAML.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top