Create object from View input and pass it to ViewModel (in MVVM) - wpf

Recently I'm developing my first project using MVVM concept (I use WPF). I've read many tutorials (ia. famous J.Smith's one) about MVVM before I started writing a code. Everything I've read had been clear until I started to code...
The problem is simple: in View layer I have a form with TextBoxes. Let's say a few TextBoxes, ie.: Name, Surname, Phone number. When user fills all of them and clicks OK-button, I want to add new person (with specified personal details) to my local Database (I use Entity Framework as a ORM).
To do this I need to write something like this:
<Button Name="MyButton" Command="MyRelayCommandWhichNeedsAllOfTheTextboxes" Content="OK" />
Using CommandParameter I can pass one object from View to ViewModel. There are many textboxes so it's probably not a good idea.
From XAML I can assign to CommandParameter whole form which needs to be filled by user. But then, inside ViewModel, I need to know all textboxes' names. The main assumption in MVVM is that all the layers (View, ViewModel and Model) have to be independent.
What's the best solution? How can I pass input data from form to ViewModel?

I would suggest having the relay command as part of your View Model -- that way, when the command gets triggered, you'll have access to all the properties you need.
XAML:
<Button Name="SurnameTextBox" Text="{Binding Surname,Mode=TwoWay}" />
<Button Name="MyButton" Command="{Binding MyRelayCommand}" Content="OK" />
View Model:
public class MyViewModel : INotifyPropertyChanged
{
// (note, raise property changed on the setter
public string Surname { get; set; }
public ICommand MyRelayCommand { get; set; }
public MyViewModel
{
// set the command callback here
MyRelayCommand = new RelayCommand(OKCommandHandler);
}
private void OKCommandHandler(object parameter)
{
// save the record here using Surname, etc
// (note that you don't even need to use parameter, so you can just ignore it)
}
}

you dont need to pass data from form to viewmodel because your viewmodel has allready all data.
your viewmodel expose all data through properties to your view and you bind to it. look at dbaseman answer.

Related

WPF / MVVM Design Suggestions

I'm pretty new to WPF, and am looking for some guidance here.
I'm working on an application that will be used to print out work orders for our fulfillment department.
Right now I have 2 windows: The first is the main screen, the second is a window with a gridview that will hold the work orders to print.
The first page will have several buttons on there. Every button will open up the second window; however, depending on which button is clicked, the parameters passed into the service that will load data will be different.
What would be the best practices way of doing this?
Is there way to define these parameters somewhere on the Button control, and then pass them through via ICommand/RelayCommand?
Should I create a UserControl/ServerControl that will let me build in these additional properties?
Something else I'm not thinking of?
Edit:
To give a rough example (and this is very oversimplified}, say i have 2 sets of criteria: OrderTypes: {Rush, Today, Future} and Locations {Warehouse 1, Warehouse 2, Warehouse 3}
The main window would have a 3x3 grid of buttons, one for each combination. I'd like to be able to specify on a single button "Expedite & Warehouse 1"; and then pass those parameters back to a single method, which would open the second window.
Lets say you have MainWindow and buttons are placed in it.
Create a MainWindowViewModel and set it as DataContext for MainWindow.
Have an ICommand on your ViewModel and bind button Command with this ICommand so that entry point for opening another window will be single. For ICommand you can use either RelayCommand or DelegateCommand whichever suits you best.
Now, comes the point where you need to open window and pass on parameter to it based on button type click. I would suggest to have Enum depicting action need to perform based on different buttons.
Enum
public enum ActionType
{
Action1,
Action2,
Action3 and so on...
}
And bind from button like this:
<Button Command="{Binding CommandInstance}"
CommandParameter="{x:Type local:ActionType.Action1}"/>
<Button Command="{Binding CommandInstance}"
CommandParameter="{x:Type local:ActionType.Action2}"/>
where local will be namespace where enum is declare.
And in command execute delegate pass the enum value to another window constructor:
private void CommandMethod(ActionType action)
{
AnotherWindow anotherWindow = new AnotherWindow(action);
anotherWindow.Show();
}
and from action passed in constructor, you can check what parameter need to pass to service responsible for loading data.
Also, in case creating window from ViewModel doesn't seems right you can have Service wrapper over window Controls which is responsible for showing/closing window.
UPDATE
Since you want to pass multiple parameters from Views so maintaining enum for this will be cumbersome. You can pass multiple values from View using IMultiValueConverter.
Let me explain with small example:
<Button Command="{Binding TestCommand}">
<Button.Resources>
<sys:String x:Key="Rush">Rush</sys:String>
<sys:String x:Key="Warehouse">Warehouse</sys:String>
</Button.Resources>
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MultiValuesReturnConverter}">
<Binding Source="{StaticResource Rush}"/>
<Binding Source="{StaticResource Warehouse}"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
where sys will be namespace for System in XAML:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
So, now you have liberty in XAML to pass many objects from XAML to your command parameter. All you have to do is to declare the resource under Button resources section and pass it as binding to converter.
Converter code to convert it into list of parameters which can be passed to command as a single parameter object:
public class MultiValuesReturnConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
return values.ToList<object>();
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
Command Method:
private void CommandMethod(object parameter)
{
// Now you have all the parameters here to take decision.
IList<object> values = parameter as List<object>;
AnotherWindow anotherWindow = new AnotherWindow(action);
anotherWindow.Show();
}
If you don't want to use some third party library, there really is no problem in simply passing the parameters through a click event into your other window's constructor. If your data is represented by a viewmodel you may also pass that viewmodel instead of the parameters themselves.
A point of MVVM is not "no code-behind". Many times you will end up without code-behind, but trying to develop applications this way leads you into convoluted anti-patterns that often are more work and more lines of code than simple click events and "the old way".
Treat your data as data, try to do all your work in testable viewmodels and never follow a pattern too rigidly lest you end up with mounds of unreadable abstractions.
Before detailing any thing, I would advice you to use the third party library MVVMLight, it has many helpful features such as Messenger, its own RelayCommands etc ...
For passing parameters from a button to consume them in Commands, you can use the Tag property if you want to pass a parameter regardless of the type of the event, if you want to pass a parameter that is related to a certain Command(event) then CommandParameter is what you need :
Tag : Gets or sets an arbitrary object value that can be used to store custom information about this element. (Inherited from FrameworkElement.)
CommandParameter :
<Button Content="Parameterized Command"
Command="{Binding ParameterizedCommand}" CommandParameter={Binding SomeObject} />
I don't think at the level of your question that you need to create a UserControl unless you have more complicated scenarios.
You can use the Messenger class to pass information from ViewModel to another (this just a helper it's independent from the MVVM Pattern).
The MVVMLight has code templates that help you create ViewModels with ease.
The MVVMLight has many helpful snippets which you will find helpful.
Beware of Commands because they are not originally supported with all UIElements, they are only available with ButtonBase and its children and they work only to replace the Click event, to use Commands and CommandParameters with other UIElements and with other kinds of events you should use a sort of EventToCommand behaviours, MVVMLight has got that already ready for you
Hope I covered most important parts you may need.
The most easy and intuitive way (Using INotifyPropertyChanged to update the UI instead of DependencyProperty):
You create a property that'll be your DataContext for your OrderViewModel in MainWindowViewModel
class MainWindowViewModel : ViewModelBase // ViewModelBase should implement INotifyPropertychanged, unless you're using dependency properties
{
private OrderViewModel _OrderViewModelInstance;
public OrderViewModel OrderViewModelInstance
{
get{ return _OrderViewModel;}
set { _OrderViewModel = value;
OnPropertyChanged("OrderViewModel")} // Method from ViewModelBase
}
Now, whichever way You're creating Your Order View:
You instantiate OrderViewModel in MainWindowViewModel (Let's say when a button gets clicked) with desired parameters.
you bind the Order view's DataContext to OrderViewModelInstance in XAML. You might want to create an additional variable that tells you when the window is visible.

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).

passing data to a mvvm usercontrol

I'm writting a form in WPF/c# with the MVVM pattern and trying to share data with a user control. (Well, the User Controls View Model)
I either need to:
Create a View model in the parents and bind it to the User Control
Bind certain classes with the View Model in the Xaml
Be told that User Controls arn't the way to go with MVVM and be pushed in the correct direction. (I've seen data templates but they didn't seem ideal)
The usercontrol is only being used to make large forms more manageable so I'm not sure if this is the way to go with MVVM, it's just how I would of done it in the past.
I would like to pass a class the VM contruct in the Xaml.
<TabItem Header="Applicants">
<Views:ApplicantTabView>
<UserControl.DataContext>
<ViewModels:ApplicantTabViewModel Client="{Binding Client} />
</UserControl.DataContext>
</Views:ApplicantTabView>
</TabItem>
public ClientComp Client
{
get { return (ClientComp)GetValue(ClientProperty); }
set { SetValue(ClientProperty, value); }
}
public static readonly DependencyProperty ClientProperty = DependencyProperty.Register("Client", typeof(ClientComp),
typeof(ApplicantTabViewModel),
new FrameworkPropertyMetadata
(null));
But I can't seem to get a dependancy property to accept non static content.
This has been an issue for me for a while but assumed I'd find out but have failed so here I am here.
Thanks in advance,
Oli
Oli - it is OK (actually - recommended) to split portions of the View into UserControl, if UI became too big - and independently you can split the view models to sub view models, if VM became too big.
It appears though that you are doing double-instantiations of your sub VM. There is also no need to create Dependency Property in your VM (actually, I think it is wrong).
In your outer VM, just have the ClientComp a regular property. If you don't intend to change it - the setter doesn't even have to fire a property changed event, although it is recommended.
public class OuterVm
{
public ClientComp Client { get; private set; }
// instantiate ClientComp in constructor:
public OuterVm( ) {
Client = new ClientComp( );
}
}
Then, in the XAML, put the ApplicantTabView, and bind its data context:
...
<TabItem Header="Applicants">
<Views:ApplicantTabView DataContext="{Binding Client}" />
</TabItem>
I answered a similar question as yours recently: passing a gridview selected item value to a different ViewModel of different Usercontrol
Essentially setting up a dependency property which allows data from your parent view to persist to your child user control. Abstracting your view into specific user controls and hooking them using dependency properties along with the MVVM pattern is actually quite powerful and recommended for Silverlight/WPF development, especially when unit testing comes into play. Let me know if you'd like any more clarification, hope this helps.

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

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.

Sharing context between view models

I am building my first silverlight application. This application has several forms that allow user to save Customers, Vendors, Staff etc. Each page has one parent usercontrol (with a corresponding viewmodel) and one or more child usercontrols (each with a viewmodel of its own). For example customer form would have Customer usercontrol as the parent and Address Usercontrol, Phone Numbers UserControl as Child usercontrols on the form. Now the parent "Customer" is responsible for ensuring the data is saved for Customer, Address and Phone when the user clicks the Save button. Behind the scenes I could share a datacontext instance between customer, address and phone number viewmodels. So when the Save button is clicked, the customer usercontrol could save data for all three (since its datacontext would have the Address and PhoneNumber entities as well).
What I would like to know how to pass this datacontext from Customer to Address and Phone Number? One way could be to pass datacontext to Address and Phone number view model in their respective constructors but then I would need to ensure the Address and PhoneNumber constructors are called only after Customer viewodel has been created. can there be a better solution? Does MEF offer any better solution?
You have the power of Silverlight client-side. Meaning: you have statics :-)
The way I did this in our most recent app was to create a ContextCache. Basically, it's a static class that holds all of my RIA contexts for use in any of my ViewModels. Like so:
public static class ContextCache
{
private static TicketContext _ticketContext;
public static TicketContext TicketContext
{
get
{
if (_ticketContext == null)
_ticketContext = new TicketContext();
return _ticketContext;
}
private set { _ticketContext = value; }
}
}
So, in a ViewModel, you just make a call to ContextCache.TicketContext and you can save changes. This way you can take advantage of all of the state change tracking in RIA and let it handle all the details for you about object persistance (if you've coded your services correctly that is, but that's another story).
Perhaps with your architecture a bad solution can be with IsolatedStorageFile which you may simulate ASP.NET's session!
From my understanding, you are trying to overuse the MV-VM pattern in your app! One of the important reason ViewModel came in our life is because of unit testable! If I were you, I would have had a Customer ViewModel and use it in all my child-usercontrols!
Depending on the complexity and isolation if child controls requires it own separate ViewModel, you may consider a parent ViewModel and have properties of the child ViewModel.
public class ParentViewModel : FrameworkElement {
Child1ViewModel Child1 { get; set; } //Must be a dependency property
Child1ViewModel Child2 { get; set; } //Must be a dependency property
ICommand SaveButtonCommand; //Your delegate command of your save button
public ParentViewModel() {
Child1 = new Child1ViewModel();
Child2 = new Child2ViewModel();
}
}
And you can use this parent view on your Parent XAML
<UserControl.DataContext>
<ViewModels:ParentViewModels />
</UserControl.DataContext>
<Controls:Child1 DataContext="{Binding Child1}" />
<Controls:Child2 DataContext="{Binding Child2}" />
You also have ICommand SaveButtonCommand in your ParentViewModel and manipulate with the properties in your child ViewModel when clicked!
Hope it helped!

Resources