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.
Related
I have an app that should display data based on variables from parameters received from calls of the ViewModel.
I have noticed two places in which the ViewModel gets called from, one is the intended call by the parent ViewModel for displaying the View of the child ViewModel with the help of ViewLocator.cs. Another is the DataContext required by the View to enable data binding.
Former: [ParentViewModel.cs]
public ParentViewModel()
{
UserControlContent = new ChildViewModel(genericParameter: "actual parameter");
}
Latter: [ChildView.axaml.cs]
public ChildView()
{
InitializeComponent();
DataContext = new ChildViewModel(genericParameter: "not the parameter I want");
}
So I want to pass in the "actual parameter" as shown above for show in the resulting View. I expect the final view to look like this:
But in reality I get this:
So, how can I work around this and get the View to display the right data?
Appreciate any input!
Turns out, only the call from the ParentViewModel is required. DataContext under ChildView can be removed and the correct parameter can be used.
Thanks to the answer here for this question.
I think you have some fundamental misunderstandings of MVVM.
Firstly, you have two ChildViewModel instances.
So calls made in your ParentViewModel on the UserControlContent instance of the view model will never be reflected in the UI as the ChildView creates a new instance of the ChildViewModel itself and then uses this instance for as it's DataContext.
You should make use of some form of IoC and DI your dependencies.
MVVM discourages the use of manual view model creation through the new keyword.
Unless there is a very specific use case, try to keep some relationship between the UI structure and your view models as flat as possible.
By this I mean if there is a use case where the parent view model needs the same things as the child view mode. It may make sense to flatten and merge those two view models.
This in turn simplifies the VMs themselves and the bindings.
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 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.
I've recently been learning the MVVM pattern in WPF and just started making my first proper, rather big application. So far it's all smooth sailing, and I'm liking what I'm seeing a lot. However I recently met something of a stumbling block.
The application is built with a main TabControl, each TabItem containing a pretty big details view.
TabControl inside main View, ItemsSource bound to MainViewModel.OpenTabs
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
etc...
The OpenTabs collection is an ObservableCollection<BaseViewModel> on MainViewModel, and the TabControl's SelectedItem is bound to MainViewModel.ActiveTab.
So far so good! However, what I'm not sure I'm getting is how to handle closing of tabs while at the same time following MVVM. If I wasn't trying to be strict with the MVVM (in order to learn it properly), I'd just bind a MouseDown-event on the TabItem-headers and thus get a reference to the clicked item in that event, removing it from the OpenTabs collection in that way. But - unless I'm mistaken - the interaction logic shouldn't need references to actual UI items in order to be effective and proper MVVM.
So, how do I handle this MVVM style? Do I use a command that sends a specific parameter with it to my MainViewModel? It seems like the preferred implementation of ICommand in MVVM doesn't take object parameters (looking at MVVM Light as well as some other tutorials).
Should I just create a CloseTab(int id) public method on my MainViewModel and call that from the view codebehind after catching the Click on my TabItem close button? This seems like MVVM-cheating. :)
Also a final note - this should work even if I click close on a TabItem that isn't the currently active one. Otherwise it wouldn't be hard to setup with OpenTabs.Remove(ActiveTab).
Thanks for any help! I'd also appreciate any links to recommended reading/watching regarding these problems.
Solution: It seems the best way is to use a command that can accept command parameters. I used the RelayCommand from MVVM Light framework:
In MainViewModel:
CloseTabCommand = new RelayCommand<BaseViewModel>((vm) =>
{
OpenTabs.Remove(vm);
});
In XAML:
<Button
Command="{Binding Source={StaticResource MainViewModel}, Path=CloseTabCommand}"
CommandParameter="{Binding}">
Note: Your binding paths may of course vary depending on how your Views and ViewModels are set up.
The best and the right way is to create the command. In different frameworks ICommand usually has two implementation, with the parameter and without one (as often you do not need it).
MVVM light has two ICommand implementation as well: RelayCommand and RelayCommand<T>
I suggest creating your own DelegateCommand implementation, a good example on how to this can be found here or here. Or use the Prism variant, you can download it here.
With a DelegateCommand you can pass arguments down to your ViewModel.
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.