I have a view that I'll call View1 that has a nested user control that I'll call View2. My main application creates and shows View1 which in turn creates View2 since it is a user control on View1. Both View1 and View2 have their own viewmodels. What I need to do is get a value from View1's viewmodel to View2's viewmodel.
View2 is meant to be a completely self-contained control with its own functionality that is reusable in any other view, but it needs a piece of information from whatever view it is contained in. In the case given here, that would be View1.
My first attempt was to create a dependency property on View2 so it could be set in View1 like so:
<myUserControls:View2 MyProperty="{Binding RelativeSource={RelativeSource Self}, Path=Parent.DataContext.MyProperty}"/>
This works to set the dependency property, but that doesn't help to get the property value into View2's viewmodel where I can work with it.
I am doing this in Silverlight, if that makes any difference.
Anyone know if there is a way to do this?
I would recommend using the "Mediator" pattern, or some sort of communication between viewmodels. I personally have used galasoft MVVM light messaging to great deals of success. Rachel has also written a pretty good blog on navigation: Rachel's MVVM blog
But I would try and decrease the coupling in your program by letting the messaging handle the data context switch and viewmodel updates as opposed to creating a dependency property.
You could for instance have a baseviewmodel class which all view models inherit from, and use a polymorphic generic "view model" property which is of type baseviewmodel in your main viewmodel. Once the message was received to switch from viewmodel #1 to viewmodel #2, call a "update model" function (which you have declared in your baseviewmodel and override in your VM #2) which will then handle updating your VM #2.
Related
I’m new to MVVM and am trying to establish good practices as I convert a large non-Model-View WinForms project. Here’s an example of a solution I’ve implemented. I’m wondering if there is a better pattern for solving this class of problem.
MyModel has ten properties. MyView exposes two of them for users to update. MyViewModel handles the usual stuff in between.
Other models depend on MyModel’s properties, so I only want to change MyModel when values are committed to. MyView has OK and Cancel buttons, so instead of having MyViewModel directly update MyModel when the user interacts with MyView, I’ve created another layer: MyTempModel. MyTempModel contains two properties which correspond to the two from MyModel.
So inside MyModel, prompting code looks something like this:
var tempModel = new TempModel{Prop1=Prop1,Prop2=Prop2};
bool? response = new MyView().ShowDialog();
if (response.HasValue && response.Value)
{
Prop1 = tempModel.Prop1
Prop2 = tempModel.Prop2
}
Thus if the user clicks ‘Cancel’, MyModel’s properties are not changed.
Note: Not shown here is that I set a reference to MyTempModel in MyViewModel once to establish that wiring. MyViewModel subscribes to property changed events in MyTempModel and MyView uses databinding to connect to MyViewModel.
model - > view data flow summary:
MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.
view -> model data flow summary:
Changes to MyView result in dependency property in MyViewModel to change. This property’s setter pushes the value to MyTempModel. When user clicks Ok then MyModel copies values from MyTempModel.
I'm particularly interested in the role of the ViewModel. I have in mind that keeping dialogs "humble" is a good thing, and maybe that is spilling over into making ViewModels humble. So comments on what kind of functionality you put into your view models vs your domain models would be especially interesting.
I appreciate any and all design wisdom for this pattern. I'll gladly update this info if anyone needs clarification.
I don't think the use of a proxy class is a bad thing. I'm a little concerned about this: 'MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.' I think that renders your Model classes a little less universal and obscures that functionality from the ViewModel. I would just use the ViewModel to mediate the swap in/out of the proxy, rather than having the Models do it. I also think that using a proxy opens up use of DataTemplates for that type which could make the UI work easier.
An alternative to the direction given by Alex is to make the viewmodel a representation of what is in both client and server side.
E.g., the number shown is always what the user entered and the background of the number indicates that this number has been confirmed or not (pending)by the server. The viewmodel could use two different properties to contain these values and a status property to indicate the fact the property has been synchronized.
This way the viewmodel captures all the user needs to know. All the view needs to do is bind to the correct properties for display and editing.
I have a button button_extract. I want to bind it to two different data contexts (2 classes in different namespaces)
I want to set the Command and IsEnabled properties to different data context.
I have one datacontext set for Command property. But how to I specify the datacontext of IsEnable property which is in different class and namespace. Here is the scenario:-
I have a project named Environments with three namespaces:Viewmodel,Data and View
Viewmodel has class A
Data has class B
View has xaml C with button button_extract.
The data context for C is set to class A.The xaml is as follows
<UserControl x:Class="Enviornment.Views.C"
DataContext="Environment.Viewmodel.A">
<Button Name="button_extract" Command="{Binding ExtractButtonClick}" IsEnabled="{Enviornment.B.SelectedEnvionment}" >Extract</Button>
The above code does not work. The binding of IsEnabled throws error. How can I set the datacontext of IsEnabled to that of Enviornment.B???
You seem to have a common misconception about WPF regarding the need to set the DataContext. In fact, there is rarely any need to set a DataContext on any control as typically the Window has had its DataContext set and each control's DataContext will automatically inherit from that.
So, how to data bind to two different places? Generally, one place would use a normal Binding Path and the other would use a RelativeSource Binding Path. However, that would be more for the case where you wanted to data bind to properties of the set DataContext and properties of a control's code behind.
It is more common in your scenario to simply prepare a view model. That is a custom class that implements the INotifyPropertyChanged interface and provides all of the properties and functionality that your Window, UserControl, or 'view' requires. You would then set an instance of this single object as the DataContext.
Therefore, simply add properties of the relevant classes into your view model and then you will be able to access them all using the one single DataContext object. Please search online for MVVM for further information.
Let's say I've got a View. It's DataContext is bound to a ViewModel and the ViewModel exposes a Model property.
Is it MVVMlike to bind fields in the View to properties in the Model (e.g. Binding Path=Model.FirstName)?
Should the Model implement INotifyPropertyChanged?
My team are using Prism and MVVM in WPF. A lot of the Prism examples bind indirectly to the Model. I personally have my doubts that this is the correct approach. I think stuff in the model should expose behaviour (not just at the property level) and should communicate important events by, er, events - that clients can subscribe to or not.
I think that by having domain/model objects implement INotifyPropertyChanged somehow says to the world that it's UI/UX aware and kind of introduces some redundancy in the ViewModels.
What do you think? What works for you? A clear distinction between View/ViewModel/Model or a hybrid as used by the Prism examples?
I have seen many people implementing INotifyPropertyChanged directly in their Model and similarly I have seen people doing it in ViewModel as well.
I prefer and do this(implement INotifyPropertyChanged) in ViewModel. I agree with you it sometimes create redundancy in ViewModel but I prefer a clear distinction/separatation between ViewModel and Model and what their purpose should be. To me Model is just literally a Model. It is just representation of my Business Data nothing more nothing less. To me it should not cause any change in View (through notify property changed event). View should talk to ViewModel and ViewModel should use Model. I don't like View directly affecting the Model. I don't like using Model.FirstName because to me it seems like going against MMVM by telling View what is in Model
I was wondering what the best approach is for sharing a menu across all wpf windows/views.
My Application doesnt really fit the navigation model, so will probably use a Ribbon control.
I am leaning towards creating a user control for the menu and dropping it on each view, but have also seen Josh Smith's msdn article, where he loads user controls.
Are there any other options or established best practices?
Thanks in Advance.
I ended up implementing in a way similar to Josh Smiths; I have however simplified things a bit.
All views are usercontrols, except the MainWindow.
The MainWindow contains a ContentTemplate which is bound to a property holding reference to a single UserControl in the view model.
I then have an ApplicationController responsible for controlling the view and view model lifecycle.
The ViewModel base class used by each view contains a reference to the IApplicationController.
The MainWindowViewModel then makes calls to the ApplicationController to load a new view etc.
Still not 100% on this approach so would welcome any further suggestions.
Here's what I would probably try:
Define an ISharedMenu interface
Create a UserControl which uses the ISharedMenu as its DataContext.
For each ViewModel that you want to use the shared menu, implement the ISharedMenu interface.
Hello fellow StackOverflow users (or Stackoverflowers?):
I'm learning-by-coding WPF. I read several articles/saw several screencasts, and coming from a WEB dev background, I fired up VS2010 and started doing a sample application that would help me learn the basics.
I read some about MVVM too, and started using it. I set up my solution to use WPF 4.0, ActiveRecord 2.1 and SQLite, and everything went kind well. But I still have some doubts:
I created a MainWindowViewModel, and am using the RelayCommand class from here to... relay the command. Am I breaking any guidelines by having a MenuItem from the MainWindow to have its command bound to a property of this viewmodel?
This action I'm binding the MenuItem command to is going to instantiate a new ViewModel and a new View, and show it. Again, is that ok in the MVVM context?
My MainWindow will be a kind of "dashboard", and I will have more than one model attached to this dashboard. Should I just wrap all those models in a single view model?
Something like this:
public class MainWindowViewModel {
private ObservableCollection<Order> openOrders;
private Address deliveryAddress;
private Order newOrder;
/* Wrappers for the OpenOrders Collection */
/* Wrappers for Delivery Address */
/* Wrappers for New Order */
/* Command Bindings */
}
TIA!
I created a MainWindowViewModel, and am using the RelayCommand class from here to... relay the command. Am I breaking any guidelines by having a MenuItem from the MainWindow to have its command bound to a property of this viewmodel?
No, you're not breaking any guideline. It's perfectly appropriate to bind the MenuItem to a command of the MainWindowViewModel (where else would you put this command anyway ?)
This action I'm binding the MenuItem command to is going to instantiate a new ViewModel and a new View, and show it. Again, is that ok in the MVVM context?
It's perfectly fine to create a new ViewModel, of course. As for creating a new view, it depends on how you create it... you should of course never instantiate a view explicitly from the ViewModel, because it would introduce a dependency of the VM to the view.
My MainWindow will be a kind of "dashboard", and I will have more than one model attached to this dashboard. Should I just wrap all those models in a single view model?
It depends on what you mean by "wrap"... Your MainWindowViewModel could expose other ViewModels through properties, and theses VMs would be displayed in different parts of the view. If that's what you mean, yes, you should wrap them.
Adding to the Thomas answer:
I would create different usercontrols for each part of the dashboard and assign a viewModel to each usercontrol.
I created a MainWindowViewModel, and am using the RelayCommand class from here to... relay the command. Am I breaking any guidelines by having a MenuItem from the MainWindow to have its command bound to a property of this viewmodel?
No, that's exactly where you put commands.
This action I'm binding the MenuItem command to is going to instantiate a new ViewModel and a new View, and show it. Again, is that ok in the MVVM context?
It shouldn't need to know how to instantiate a new view; that's the view's job. The specifics of how to do this depend on how you're showing this new view - it could be as simple as having a ContentPresenter in the view that's bound to a property in the view model, so when you set the property (and raise PropertyChanged) the ContentPresenter renders the new object with its related DataTemplate.
Things get a little hinky if by "instantiate a new view" you mean "open a new window." There's not an especially elegant way to do this, especially if you want the new window to be a modal dialog. One way is to add an event handler to the view's code-behind that listens to PropertyChanged on the view model; when the subordinate view model property gets set, the code in the view creates and shows the new window.
My MainWindow will be a kind of "dashboard", and I will have more than one model attached to this dashboard. Should I just wrap all those models in a single view model?
Sure. That's a really common pattern. It's not at all uncommon, for instance, to expose an observable collection property and bind an ItemsControl of some kind to it; the view will automagically create views for every view model you put in that collection. Again, the specific implementation really depends on your application.