I have a silverlight control (View) which displays a list of items in a specified property of the datacontext (viewmodel).
What I need is for the scrollviewer in my control to scroll to the top or bottom depending on where the latest item has been added to the list. (It'll always be either the beginning or the end of the list, I don't need to worry about middle of list insertions.)
In WPF i'd just use the DataContextChanged event to start listening to the viewmodel, but in silverlight that event is internal.
Any ideas on how to tackle this?
A good starting point is Attached Behaviors on CodeProject.
A useful behavior would watch the ListBox.ItemsSource and attach to the observable collection when set. On the collection changed event, use ListBox.ScrollIntoView to display the changed item.
I can't use the CollectionChangedEvent of ObservableCollection since I need the DataContextChanged event to get the DataContext which holds the Collection in the first place.
Would you not do this in the ViewModel?
Whatever ViewModel has the ObservableCollection, expose a property of type T named SelectedItem and whenever the ObservableCollection changes with a new item, the CollectionChanged event will allow you to set the SelectedItem property. Once this is done, wire up the SelectedItem in the control to this property on your ViewModel.
This will obviously only work with controls like ListBox where a SelectedItem property exists.
In place of DataContextChanged in WPF , you can use CollectionChanged event of ObservableCollection. In the collection changed you will get to know the NewItem Index.
Related
I have two DataGrids bound to the same ObservableCollection property in my ViewModel.
When I edit an existing row in one DataGrid another gets updated after row is commited.
But how it works? The NotifyCollectionChanged event is not raised on the underlying ObservableCollection. I have checked it by subscribing to the event.
In this case, you are modifying the properties of the item (entity) of the collection, not the collection itself.
Therefore, the CollectionChanged event is not raised.
To update properties in an entity, INotifyPropertyChanged must be implemented in it.
But if the change of properties happens ONLY through bindings, then even this is not necessary.
Bindings use PropertyDescriptor and other types of reflection in their work.
This allows bindings to "know" that a property has been changed by another binding.
If you speak Russian, read my article: https://www.cyberforum.ru/wpf-silverlight/thread2650880.html
I have a View with a dataGrid. This datagrid bind a property in the ViewModel that is an ObservableCollection.
I edit some data in the dataGrid, and a field is updated by code, because it depends on some operations. Well, if I check the item in the observable collection, I can see that all the data is correct, but the info in the dataGrid is no refresh.
I want to force the refresh because I know that the observableCollection only raise the change property event when I add o remove items, but not if I edit one of them.
Because I am use Entity Framework 4.1, really the ItemsSource of the dataGrid is the local of the DbSet, so I don't know how to implement the notifyPorpertyChanged in the classes of the model edmx, and I am looking for an alternative, like to force refresh the dataGrid.
Because the property of the ViewModel that I use to bing the ItemsSource of the dataGrid is a reference to the local, I mean that to set the property I do myProperty = myContext.MyTable.Local and that raise the event PropertyChanged that I implement in my ViewModel, I try to do myProperty = myContext.MyTable.Local again to try to raise the event and force the refresh of the dataGrid, but it does not work.
What alternatives do I have?
Make sure that you have the Binding Mode set to TwoWay. Implement in the set portion of your property OnPropertyChanged and the rest should take care of itself.
Calling OnPropertyChanged for an ObservableCollection only works when there has been some change to the properties of the collection, not the objects it contains (add, remove, clear, etc).
Is there any way to notify the View that there has been a change to an item within the collection?
The objects it contains have to implement INotifyPropertyChanged as well. In your setter you trigger the event, and WPF will pick up on this and read in the new value as long as you are using two-way bindings or read-only bindings.
Kind of an odd question- if I'm thinking of this the wrong way please let me know. I am using an infragistics dock manager, which manages tabs as well. So I can create a TabGroupPane, and then add multiple ContentPanes, each of which has its own tab.
In each content pane, I set my viewmodel:
<ContentPane>
<viewmodels:MyViewModelForTab1 />
</ContentPane>
So here's the problem- while using a mediator pattern for communication, my viewmodels have no idea if they are on the visible tab or not, so they are always working even if hidden. The TabGroupPane does have a SelectedTab property, as well as each ContentPane having an IsActive property.
So the question is how do I set that information in my ViewModel? Making my VM a dependency object seems like a bad idea since I already implement INotifyPropertyChanged. Using a CLR prop in my VM also doesnt work, since you cannot bind to it.
How can I get my VM to know if it is the datacontext of an active tab?
Thanks!
I would put an IsSelected property on my ViewModel and bind it to the TabItem's IsSelected dependency property.
This should allow you to hook into when it is updated and perform whatever you need. You don't need a mediator pattern here since you are communicatining from the View to the ViewModel.
Make sure your ViewModel is bound to the DataContext property of the view (specifically, that the Tab's DataContext is the ViewModel). The way you have it now, your ViewModel is the content of the element, not bound to the DataContext, as it should be:
<Tab.Resources>
<viewmodels:MyViewModelForTab1 x:Key="Tab1ViewModel" />
</Tab.Resources>
<ContentPane DataContext="{StaticResource Tab1ViewModel}" />
Or something like that...
I don't know the Infragistics model, so my apologies if this is inapposite, but here's how I implement this with regular items controls - tab control, list box, whatever.
Create a container view model class that includes an observable collection of items and exposes a SelectedItem property. Make the container class the data context of the items control. Bind the items control's SelectedItem property to the container class's.
Hook the item objects up to the PropertyChanged event of the container. So now when the selected item in the UI changes, the container view model notifies all of the items that SelectedItem has changed. Each item object's event handler can determine for itself whether or not it's now the selected item.
The item objects thus don't know any implementation details of the UI - you can unit test your classes outside of a UI and the logic will still work correctly.
I have a control that is data-bound to a ListBox. All of the bound properties are being updated correctly. However, the control needs to know when the selected item changes so that it can do some other cleanup. Is there an event that covers this?
You can also bind to the SelectedItem property, say with ICollectionView.CurrentItem, and set the IsSynchronizedWithCurrentItem property to True.
There is SelectionChanged event in ListBox.