MVVM: Giving every modular part it's own XAML class - wpf

I was thinking about doing this instead defining lot's of DataTemplates. This would mean that if I had a collection of things the ItemsControl itself would have a XAML class and the objects would have one too.
This is something that already happens when the objects are proper ViewModels containing models and logic but if it's just a Command for example. A dynamic group of commands perhaps.
Pros: I could use the designer to help me define the look of the object as I don't have blend and it would be easier to find and change those parts if needed.
Cons: More XAML classes.
Would you talk me into this or out of this.
EXAMPLE
I have buttons all around the app so I define a ButtonViewModel which has a display name and a ICommand Property. I would also define a DataTemplate or UserControl for this object which would basically be a button with Command binding and text/content binding to the display name. I could also define it's look and such.
Then in ViewModels that should include buttons I would add these buttons as part of the class and bind to them inside the view.
public class ButtonViewModel : ViewModelBase
{
private string _displayName;
public string DisplayName
{
get
{
return _displayName;
}
set
{
_displayName = value;
RaisePropertyChanged("DisplayName");
}
}
private ICommand _command;
public ICommand command
{
get
{
return _command;
}
protected set
{
_command = value;
RaisePropertyChanged("Command");
}
}
public ButtonViewModel(ICommand command, string displayName)
{
Command = command;
DisplayName = displayName;
}
}
ViewModel using the ButtonViewModel
public class SomeViewModel : ViewModelBase
{
//some functionality
//It could be done as a collection or just seperate ButtonViewModel properties
public ObservableCollection<ButtonViewModel> Buttons { get; set; }
//Somewhere where it makes sense, here in the constructer for the heck of it
public SomeViewModel()
{
Buttons.Add(new ButtonViewModel(new RelayCommand(Save, canSave), "Save"));
Buttons.Add(new ButtonViewModel(new RelayCommand(Edit, canEdit), "Edit"));
Buttons.Add(new ButtonViewModel(new RelayCommand(New, canAddNew), "New"));
}
}
The buttons view:
<UserControl x:Class="WpfApplication1.ButtonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="60" Width="90">
<Button Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}">
<!-- Some really cool design for your button -->
</Button>
</UserControl>
You could also define a specific ItemsControl to hold a collection of buttons, even going so far as to define a ViewModel for said itemscontrol.
I once learned that if you can encapsulate some item in a class you should. Is this just crazy talk?

I'm not quite sure what you're asking, but it sounds as if you are taking a view first approach, which can get very complex in everything but the simplest of apps. Have you considered using an MVVM framework such as Caliburn.Micro?
Using a view model first approach, you can instantiate your view model, and then use Caliburn.Micro to locate your view (via convention), and automatically bind the two up.
Caliburn.Micro will also do view composition, so for example, if you have a collection of view models on your parent view model, and you expose that collection from a property with the same name as a ListBox on your view, then Caliburn.Micro will automatically use the corresponding view for each item in the collection, and bind up each items view model with the view.
You can also use different views over the same view model, and Actions are used to invoke verbs on your view models from view controls, rather than commanding, which allows for much richer imagining of UIs.

Related

Removing UserControl code behind for use with MVVM

I am trying to create a user control using MVVM.
Basically I am trying to wrap a combobox that will pull data from a respository. This will allow me to use the same combobox in many different views in my application. There will be many of the wrapped comboboxes throughout the application.
I was easily able to create this control using a DependencyProperty and code-behind. I am now trying to convert this to MVVM and am having trouble figuring out how to get the value back to /from the ViewModel that in bound to the View where my combobox is located.
Any ideas or suggestions would be greatly appreciated at this point.
Thanks,
Eric
It is perfectly acceptable to use a UserControl that has code behind in it when using MVVM. If you really want to move the functionality out of the UserControl, then move it to whichever parent view models will require it. If you don't want to have the same code repeated in several places, you could encapsulate it in a class and add an instance of that class as a property to each of the relevant view models.
if you have a viewmodel that will pull data from a respository - you can use the same viewmodel in many different viewmodels in your application :)
and if you use a datatemplate your views know how to render this viewmodel
<DataTemplate DataType="{x:Type local:MyPullDataViewmodel}">
<view:MyCoolPullDataShowComboboxUserControl />
</DataTemplate>
It's pretty easy.
Let's say you have:
MyUserControlView.xaml
MYUserControlViewModel.cs
MyMainWindowView.xaml - For your MainWindow view (the one containing the UserControl)
MyMainWindowViewModel.cs - Your MainWindow ViewModel.
And you want to bind List<string> MyListToBind
And leave the code-behind completely empty.
MyUserControlViewModel.cs
public class MyUserControlViewModel
{
private List<string> _MyListToBind;
public List<string> MyListToBind { get; set;}
}
MyMainWindowViewModel.cs
public class MyUserControlViewModel
{
private MyUserControlViewModel _MyControlViewModel;
public MyUserControlViewModel MyControlViewModel { get; set;}
}
MyMainWindowView.xaml
<Window ...
xmlns:my="clr-namespace:NamespaceContainingYourUserControlView>
<my:MyUserControlView DataContext = "{Binding Path= MyControlViewModel}"/>
</Window>
MyUserControlView.xaml
<UserControl ...>
<DataGrid ItemsSource = "{Binding Path= MyListToBind}" .../>
...
</DataGrid>
</UserControl>
This doesn't support ViewModel updating View. To do that You have to use either DependencyProperties as you did instead of normal variables (as i did) or use INotifyPropertyChanged(google it, you'll get tons of examples) and OnPropertyChanged event.
You might read up on DataTemplates they are really useful in data binding.
You can find this usefeul:
http://www.youtube.com/watch?v=BClf7GZR0DQ
I sure as hell did !
Good luck.

How should I populate the ViewModel in WPF?

I'm new to WPF and I'm writing a simple test app to familiarize myself with it. My test app will detect all joysticks I have attached to my computer and display information about it. So far, I have this ViewModel:
public class JoystickViewModel
{
public ObservableCollection<Joystick> Joysticks { get; set; }
public JoystickViewModel()
{
GetAttachedJoysticks();
}
private void GetAttachedJoysticks()
{
// populate Joysticks collection by using SlimDX
}
}
And this is my codebehind for my MainWindow.xaml:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new JoystickViewModel();
}
}
And my XAML for MainWindow:
<Window ...>
<Grid>
<ComboBox ItemsSource="{Binding Joysticks}"
DisplayMemberPath="Information.ProductName"/>
</Grid>
</Window>
I followed a tutorial that also populated the ViewModel in its constructor.
My question is, how should I populate the ViewModel? It seems sort of weird to me that I'm population the collection in the ViewModel constructor. Should this logic be in MainWindow's codebehind instead? Or somewhere else altogether? The end goal is to not only have this collection populated, but also updated periodically to reflect the current state (user plugged in new joystick, unplugged existing one, etc...).
The MainWindow code behind is definitively not the place where "business" logic should occur, as the View should be kept as simple as possible.
Keep your fetch/update logic inside of your viewmodel, this way you can test it easily and independently.
From a learning perspective, it's important to keep concerns separated :
the View is bound to the ViewModel, and has no intelligence
the ViewModel has knowledge on how to get the Model
the Model represents the data
In your case, the VM knowledge is at the moment a call inside it's constructor. Later you can change this to call some IJoystickDataService interface, and wire everything using a MVVM framework.
I would have your JoySticks observable collection property (and the code that populates it) in a Model class. The viewmodel simply exposes this same property to the view for binding. The vm should be as thin as possible - ideally just exposing properties that are in the model for binding and not doing any kind of 'business' logic (i.e. populating joystick info as in your case).

WPF Dependency Property workaround

There are 3 UserControls under a MainWindow. Each control have it's own Save Button. The Mainwindow has a SaveAll button.
The MainWindow has a ContentControl and the content property is binded to the VM. At runtime on ButtonClickCommand, the View is instantiated and assigned to the Content Property.
This SaveAll button will internally call methods associated with UserControls Save button. As such, SaveAll doesn't have it's own Method.
This has to be implemented by DependencyProperty.
I had once seen this scenario implemented in a Business App, but somehow missed the concept behind it.
I can't get what was the logic behind this, but it's a very useful thing.
Now I have to implement this, but i'm missing a small thing, I dont know.
I hope the scenario is clear.
Please help me in this scenario, with code.
Thanks,
VJ
Since you mentioned MVVM, here's what you might be looking for. Mind you, this will be a lot cleaner and easier if you use an MVVM framework such as Caliburn, but for this sample, its just vanilla MVVM:
public class MainViewModel
{
public MainViewModel()
{
ViewOneModel = new SubViewModel();
ViewTwoModel = new SubViewModel();
Children = new List<SubViewModel>(new[] { ViewOneModel, ViewTwoModel });
}
public void SaveAll()
{
foreach(var child in Children)
{
child.Save();
}
}
public IList<SubViewModel> Children { get; private set; }
public SubViewModel ViewOneModel { get; set; }
public SubViewModel ViewTwoModel { get; set; }
}
public class SubViewModel
{
public void Save()
{
}
}
and on the UI you basically have subviews (UserControls) composed in your main view:
<StackPanel>
<Button Width="100" Height="20" Content="Save All" />
<local:ViewOne DataContext="{Binding ViewOneModel}" />
<local:ViewTwo DataContext="{Binding ViewTwoModel}" />
</StackPanel>
You just need to bind the save methods to your buttons using an ICommand interface (preferably RelayCommand instance).
Imho in this scenario there is no need for RoutedEvents. The way I would solve it:
There is a Main-ViewModel that exposes 3 properties with the Sub-ViewModels.
The MainViewModel is the Datacontext for the window, and the subviewmodels bound to the datacontext of the 3 usercontrols.
The sub vm's are exposing a property with a Save-Command. This command is bound to the save buttons in the usercontrols.
The main vm is exposing a property with a saveall-command, which is bound to the SaveAll button.
In the handler of the save all command you are then iterating over the sub-vm's and call save on them.

Prism MVVM - How to pass an IEventAggregator to my ViewModel

recently I started working with Prism in Silverlight. I want to use the EventAggregator to Subscribe and Publish events between two ViewModels. As I saw on some guides, the ViewModel's ctor should accept IEventAggregator as a parameter. I can't find out how to do this hence my View always wants to initialize the ViewModel with a parameterless ctor.
My ViewModel ctor:
MyViewModel(IEventAggregator eventAggregator)
{
// get the event....
}
My View:
<UserControl ....>
<UserControl.Resources>
<ViewModels:MyViewModel x:Key="MyViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MyViewModel}}">
....
<Grid/>
</UserControl>
I can instantiate the ViewModel in the ctor of the View, and then assign it to its DataContext, but then I must have an IEventAggregator in my View, which I also cannot get. but this is probably not the correct way to pass an IEventAggregator (or any other object! - IUnityContainer for example) to the ViewModel.
Can someone tell me what I'm doing wrong?
You have to resolve your dependency via unity. Have a look at the prism MVVM examples and the ui composition. There the view does not create the view model, but it is exactly the other way round. The view model gets the view injected via constructor injection. The view model sets itself as view model for the view:
public interface IView
{
IViewModel ViewModel{get;set;}
}
public interface IViewModel { }
public View:UserControl, IView
{
public IViewModel ViewModel
{
get{return DataContext as IViewModel;}
set{DataContext = value;}
}
}
public ViewModel:IViewModel
{
public ViewModel(IView view, IEventAggregator eventAggregator)
{
view.ViewModel = this;
//get the event...
}
}
Using this approach you have to register the view model and the view to unity. Afterwards you only have to resolve the view model, the view is injected by the container.
To get the view to the right place on the user interface you have to register the view to a region using the RegionManager. When this is all set up, creating a new view model instance results in adding the view into the registered region so that it shows up on the user interface.
Other than having the ViewModel hook itself into the data context of the view (which I don't like at all), there are two other options that I can think of in Silverlight.
Utilize the ServiceLocator pattern to allow your static resources to create themselves via the container. MVVMLight has a fairly good pattern for this.
Use a framework like Caliburn.Micro, which plugs in a nice set of conventions that will wire up many things based on naming conventions, including bindings and viewmodels.
Maybe you've solved it already but
http://www.emileinarsson.se/silverlight-4-mvvm-prism-unity-dependency-injection/
this post explains how to use Unity in a MVVM environment.

WPF + MvvM + Prism

I am new in the Wpf & Mvvm world , but I have found a couple of examples and just found that there is some different way to instantiate the model. I would like to know the best/correct way to do it. both ways are using Unity
What I've foud:
var navigatorView = new MainView();
navigatorView.DataContext = m_Container.Resolve<INavigatorViewModel>();
m_RegionManager.Regions["NavigatorRegion"].Add(navigatorView);
What I did:
var navigatorView = m_Container.Resolve<MainView>;
m_RegionManager.Regions["NavigatorRegion"].Add(navigatorView);
and I changed the constructor to receive viewmodel so I can point the datacontext to it:
public MainView(NavigatorViewModel navigatorViewModel)
{
this.DataContext = navigatorViewModel;
}
Other examples I've found another way like:
...vm = new viewmodel
...m = new model
v.model = vm;
get/set DataContext
cheers
I like Igor's suggestion, but without the viewmodel having knowledge of the view. I prefer my dependencies to go one direction (View -> ViewModel -> Model).
What I do is ViewModel-First and just DataTemplate the viewmodel. So I do this:
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
region.Add(mainViewModel, "MainView");
region.Activate(mainViewModel);
With the addition of the ViewModel -> View mapping done with a WPF datatemplate (I don't think this approach is possible with Silverlight, though)
App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type viewModels:MainViewModel}">
<views:MainView />
</DataTemplate>
</Application.Resources>
That's it! I love this approach. I like the way it feels like magic. It also has the following advantages:
Don't have to modify constructors to suit the mapping
Don't have to register type for IMyViewModel in the container... you can work with concrete types. I like to keep my registrations to application services like IViewRegistry or ILogger... those kinds of things
You can change the mapping using resources scoped to a particular view that a region is in (this is nice if you want to reuse your ViewModels but want them to look different in different areas of the application
What you got there makes sense and in both cases is a View-first approach to creating a viewmodel. I.e. the view creates the ViewModel. In the original example the viewmodel is created outside of the view (and is sometimes referred to as marriage pattern), but as far as I am concerned that's the same thing - creation of the view creates the ViewModel.
If this suits your needs stick with it. Another approach you might look into is ViewModel first where the viewmodel takes a dependency on the view like so:
//In the bare-bones(i.e. no WPF dependencies) common interface assembly
interfac IView {
void ApplyViewModel(object viewmodel);
}
interface IMainView : IView {
//this interface can actually be empty.
//It's only used to map to implementation.
}
//In the ViewModel assembly
class MainViewModel {
public MainViewModel(IMainView view) {
view.ApplyViewModel(this);
}
}
public partial class MainView : UserControl, IMainView {
void ApplyViewModel(object viewmodel){
DataContext = viewmodel;
}
}
Then you can inject this view like so:
IRegion region = regionManager.Regions["MainRegion"];
//This might look strange as we are resolving the class to itself, not an interface to the class
//This is OK, we want to take advantage of the DI container
//to resolve the viewmodel's dependencies for us,
//not just to resolve an interface to the class.
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
region.Add(mainViewModel.View, "MainView");
region.Activate(ordersView.View);

Resources