Shawn
Shawn

Reputation: 185

WPF Data Binding with multiple controls

In WPF, I'm trying to bind multiple controls, but the second control isn't changing when the first control is changed.

I have two classes: a Task class, and a Log class, which is stored as a collection in the Task class. The list boxes below are bound to the Tasks, and the inner Logs for the selected Task.

The problem is that the list boxes are populated fine at first load, but if I select a different task, I'd expect the Logs to be update to the collection for the new Task, but it doesn't change from those from the originally selected task on first load. What am I missing?

In the designer:

    <ListBox x:Name="listBoxTasks" ItemsSource="{Binding}" DisplayMemberPath="Key"
             Grid.Row="0" Grid.Column="0" Grid.RowSpan="2">
    </ListBox>
    <ListBox x:Name="listBoxLogs" 
             ItemsSource="{Binding Logs}" DisplayMemberPath="EntryDate"
             Grid.Row="1" Grid.Column="1">
    </ListBox>

In the code behind:

public MainWindow()
        {
            InitializeComponent();

            IMongoCollection<Task> tasks = DataManager.GetData();

            this.DataContext = tasks.AsQueryable();
        }

The Task class:

public class Task : BusinessBase<Task>
{
    public ObjectId _Id { get; set; }
    public string Key { get; set; }
    public string Description { get; set; }
    public string Summary { get; set; }
    public string Details { get; set; }

    public IEnumerable<Log> Logs { get; set; }
    public IEnumerable<Link> Links { get; set; }
    public IEnumerable<String> RelatedKeys { get; set; }
    public IEnumerable<TaskItem> Items { get; set; }
}

Upvotes: 1

Views: 1747

Answers (5)

brunnerh
brunnerh

Reputation: 184296

It looks to me like the second binding should not work at all, as the DataContext is an enumerable of Tasks and the enumerable itself has no property called Logs. You could try working with IsSynchronizedWithCurrentItem and a binding to the current item:

<ListBox x:Name="listBoxTasks" ItemsSource="{Binding}" DisplayMemberPath="Key"
         Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"
         IsSynchronizedWithCurrentItem="True"> <!-- Set this -->
</ListBox>
<ListBox x:Name="listBoxLogs" DisplayMemberPath="EntryDate"
         Grid.Row="1" Grid.Column="1"
         ItemsSource="{Binding /Logs}"> <!-- Note the slash which indicates a binding to the current item -->
</ListBox>

You could also bind to the SelectedItem of the other ListBox but this introduces a redundant dependency between the controls. Also note that if you change any property in your data-objects you need to implement the interface mentioned by the other answerers, INotifyPropertyChanged.

Upvotes: 2

Shawn
Shawn

Reputation: 185

I have it all working now. I implemented INotifyPropertyChanged, although that didn't solve the problem.

I am now using the MVVM pattern. This helped...the NoRM library I was using didn't have a SelectionChanged event. I created a View Model and was able to convert those Models to ObservableCollections. Now I'm just setting the Logs control DataContext on selection changed for the Task class.

Upvotes: 1

Saber Amani
Saber Amani

Reputation: 6489

You have to bind your first ListBox SelectedItem to object of Task model and add event handler for SelectionChanged. inside the this event you have to populate your logs by selected Task model also you have to implement INotifyPropertyChanged in your class.

Upvotes: 2

Tom Studee
Tom Studee

Reputation: 10452

Your task class need to implement INotifyPropertyChanged

http://msdn.microsoft.com/en-us/library/ms743695.aspx

Upvotes: 2

Haris Hasan
Haris Hasan

Reputation: 30097

Your Task class need to implement INotifyPropertyChanged interface so that as soon as there is any change in the underlying data it can tell WPF UI that something has changed now update/refresh your controls agains

Upvotes: 2

Related Questions