I am trying to add my own ItemsSource to provide a list of GraphViewModels to a chart. I dont think I have it quite right though, as when I create my first GraphViewModel and add it to the Graphs, my DP is updated, but OnGraphsCollectionChanged is not called.
How is this supposed to work? If I add graphs to my VM property via a button tied to a command then all is good.
Here is the DP code, can anyone explain how this is supposed to work or what Im doing wrong to display my data during initialization?
public static readonly DependencyProperty GraphsProperty =
DependencyProperty.Register("ItemsSource",
typeof(ObservableCollection<GraphViewModel>),
typeof(DynamicPlotter),
new FrameworkPropertyMetadata(new PropertyChangedCallback(ChangeGraphs)));
public ObservableCollection<GraphViewModel> ItemsSource
{
get { return (ObservableCollection<GraphViewModel>)GetValue(GraphsProperty); }
set
{
SetValue(GraphsProperty, value);
ItemsSource.CollectionChanged += new NotifyCollectionChangedEventHandler(OnGraphsCollectionChanged);
}
}
public static void ChangeGraphs(DependencyObject source, DependencyPropertyChangedEventArgs eventArgs)
{
(source as DynamicPlotter).UpdateGraphs((ObservableCollection<GraphViewModel>)eventArgs.NewValue);
}
private void UpdateLineGraphs(ObservableCollection<GraphViewModel> grphs)
{
this.ItemsSource = grphs;
}
private void OnGraphsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{开发者_运维问答
// This never gets called when you set the ItemsSource, but is where all the work is done
}
CollectionChanged only gets called when the collection changes, if the collection is already populated prior to being set you will never get your notification, until something gets added/removed.
Secondly, if you are setting the dependency property from xaml the getter/setter is not used, the dependency mechanism uses its own internal setter routines. You should attach your collectionChanged event in your ChangeGraphs property callback function as this is called whenever the property is set/changed. You can use this to unhook the old collectionChanged event as well, the event arguments will give you an old and new value.
But really, it is an observable collection you should not have to know when the collection changes as you should be binding to the collection and when it changes the binding mechanism will update your ui.
I would change my code to look like this
public ObservableCollection<GraphViewModel> ItemsSource {
get { return (ObservableCollection<GraphViewModel>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableCollection<GraphViewModel>), typeof(DynamicPlotter), new UIPropertyMetadata(null, (o, e) => { ((DynamicPlotter)o).ItemsSourceChanged(); }));
private void ItemsSourceChanged() {
if (this.ItemsSource != null){
//attach the collection changed listener, this will listen to all FUTURE collection changes, items that are added and removed
this.ItemsSource.CollectionChanged +=new NotifyCollectionChangedEventHandler(ItemsSource_CollectionChanged);
//do some inital processing with the items that are in the collection already when it is set
this.UpdateGraphs(this.ItemsSource);
}
private void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e){
//this will get called if an item gets added or removed from the collection
}
精彩评论