This little bit of code will help me describe my problem:
public class Car
{
...
}
public class CarQueue : ObservableCollection<Car>
{
public IEnumerable Brands
{
get { return (from Car c in this.Items select c.Brand).Distinct(); }
}
}
Ok now I have an instance of CarQueue class bound to a DataGrid. When I add a Car object to the queue the datagrid updates fine by itself, but I also have a listbox bound to the 'Brands' property which doesn't update. Here is a simple sequence of code to explain:
CarQueue cq = new CarQueue();
DataGrid1.ItemsSource = cq;
ListBox1.ItemsSource = cq.Brands; // all above done during window load
...
Car c;
cq.Add(c); // datagrid updates, but not listbox
Does the listbox not update because it is bound to a property with dynamic LINQ query?
One other thing I tried was inheriting INotifyPropertyChanged and adding a new event handler to the CollectionChanged event (in my CarQueue constructor):
this.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(CarQueue_CollectionChanged);
Then in the event handler:
void CarQueue_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
PropertyChanged(this, new PropertyChangedEventArgs("Brands"));
}
This didn't work either. So does anyone kn开发者_开发知识库ow what the problem is? Thanks
There are a couple of problems here.
The Brands property is a sequence built on the fly by LINQ when it is asked for it. WPF only asks for it during the initial binding: it has no way of knowing that if it were to ask again it would get a different answer, so it doesn't. To get WPF to track changes to the Brands collection, you would need to expose Brands as a collection, and have INotifyCollectionChanged implemented on that collection -- for example by making Brands an ObservableCollection. One way to do this is using Bindable LINQ.
As an alternative, your second approach, of raising a PropertyChanged event for Brands, can be made to work. However, in order for this to work, you have to bind ItemsSource to Brands. (At the moment, you are assigning it, which means WPF forgets where the collection came from and just keeps its private copy of the values.) To do this, either use the {Binding} markup extension in XAML:
<ListBox ItemsSource="{Binding Brands}" /> <!-- assumes DataContext is cq -->
or use BindingOperations.SetBinding:
BindingOperations.SetBinding(ListBox1, ListBox.ItemsSourceProperty,
new Binding("Brands") { Source = cq });
精彩评论