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.
Related
I am currently using an ItemsControl at the top of my application that contains a few buttons, bound to a list of ViewModelBases. These VMs are the pages of my app. When clicked, they set the current page to the appropriate page. A content presenter shows the current view model, and a DataTemplate converts it into the correct view.
How can I use Data Binding in these views? Since the view is being created by the ViewModel, doesn't that mean I can't create a new instance of that view model in the view? How can it find the correct instance to bind to? Or, is it automatically bound?
WPF ItemsControls automatically set the DataContext of each Item they render on screen to their corrsponding Item in the underlying collection. This means that, if you have an IEnumerable set as the ItemsSource of an ItemsControl (or any other ItemsControl-derived class, such as ListBox), it will render every item on screen (using any available DataTemplates) and automatically assign the DataContext property of the resulting visual elements to each of the ViewModelBase Items.
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.
My first question here on the Stack. Forgive me for the bad explanation in advance.
I am working on my first MVVM application (Silverlight). I have a custom user control that contains a ListBox to show navigation items. This control is placed in my main xaml page. I don't know if I need to create a composite view model (my main page view model) with a view model especially for the custom control in it or if there is some way to elevate the ListBox properties that I need to bind to.
Through XAML I don't know how to bind, let's say, the ItemsSource property of the ListBox inside the custom control to my main page viewmodel. Basically, I'm at the point that I am questioning my design decision for trying to bind the custom control through my main page view model.
What I have done so far is create dependency properties for the custom control and try to tunnel those dependency properties down to the ListBox properties. I've achieved success with this method for ItemsSource but am having issues with SelectedItem.
Even if I do get SelectedItem to work, it still feels Wrong. Thanks for any advice in advance.
The UserControl should inherit the DataContext from its parent control, unless you are setting it directly. You can then bind to the properties on your view model from your UserControl.
If you would like to create a ViewModel specifically for the UserControl, you can also do that. You would then expose it as a property on your main ViewModel, and bind to it in the MainPage. Example:
public class MainViewModel
{
public ChildViewModel ChildInfo { get; private set; }
}
And then in the view:
<Grid>
...
<lcl:ChildView DataContext="{Binding ChildInfo}" />
...
</Grid>
Your ChildViewModel would then contain properties like SelectedItem to bind your ListBox to.
I have a WPF window that has a datagrid and a user control for a form for the fields in that datagrid. The user control and the WPF window have view models.
The user control's DataContext is bound to one of the window's view model's member field, whose value changes during the data grid's Selection Changed event.
I'm not sure if this is the right way to do it because I am unable to create references from the inner view model to the outer view model for some reason. Constructor injection won't work because I'm required to use default constructor only, and I can't seem to put a property injector in the right place (always getting null reference when I try to use it).
I am also unable to get my property change notification to work properly in the inner view model.
Is there a better way to wire my view models so that they automatically change the values in the user control when a new row is selected in the datagrid? I have a feeling that binding to the control's DataContext is not the way to go.
This doesn't seems a complex/nested scenario. Looks like pretty much a normal master details scenario. Suppose you want to edit Customer data, I would have an ObservableCollection instance bind to the DataGrid, and there will be a SelectedCustomer property in the VM also. In the DataGrid you can set SelectedItem twoway bind to the SelectedCustomer property which makes SelectedCustomer always updated with your selection. Since the usercontrol has the same instance of customer as in the DataGrid row, whenever you change anything in the UC those data will get reflected in the grid. Ofcourse all those properties should fire NotifypropertyChanged.
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.