After my wonderings on the events registration (you can find here ViewModel Event Registration and ViewModel Lifetime), now I'm thinking about viewmodel tombstoning:
In case of Tombstoning, is the ViewModel serialization a good approach ?
I'm thinking about the case in which different viewmodels have a reference to the same class. In case of Viewmodels serialization and deserialization the referenced class instance could have duplicated instance, isn't it ?
Wouldn't be better to have specialized state classes whose unique purpose in to contain all the app data, everyviewmodel get data (i mean reference to the data) from there and update the data in there and the app think only to serialize those specialized class ?
Any experience on this subject is appreciated.
Regards
SkyG
Caliburn Micro has a lot of this built in to the framwork allowing you to save properties of a view model or the entire graph to both phone state and app settings. You just need to create a class and inherit from StorageHandler.
public class PivotPageModelStorage : StorageHandler<PivotPageViewModel>
{
public override void Configure()
{
this.ActiveItemIndex().InPhoneState().RestoreAfterViewLoad();
}
}
And to your other posted question. CM has a nice way of handling the forced view first approach on the phone. It allows you to do page navigation by specifying the VM and it will handle the rest. And as a bonus, if you specify parameters to pass CM will pull them off the query string and populate properties on the target VM.
public void GotoPageTwo()
{
navigationService.UriFor<PivotPageViewModel>().WithParam(x => x.NumberOfTabs, 5).Navigate();
}
Related
I am using MVVM light and figured out since that the ViewModelLocator can be used to grab any view model and thus I can use it to grab values.
I been doing something like this
public class ViewModel1
{
public ViewModel1()
{
var vm2 = new ViewModelLocator().ViewModel2;
string name = vm2.Name;
}
}
This way if I need to go between views I can easily get other values. I am not sure if this would be best practice though(it seems so convenient makes me wonder if it is bad practice lol) as I know there is some messenger class thing and not sue if that is the way I should be doing it.
Edit
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<ViewModel1>();
SimpleIoc.Default.Register<ViewModel2>();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public ViewModel1 ViewModel1
{
get
{
return ServiceLocator.Current.GetInstance<ViewModel1 >();
}
}
Edit
Here is a scenario that I am trying to solve.
I have a view that you add price and store name to. When you click on the textbox for store name you are transferred to another view. This view has a textbox that you type the store you are looking for, as you type a select list get populated with all the possible matches and information about that store.
The user then chooses the store they want. They are transferred back to the view where they "add the price", now the store name is filled in also.
If they hit "add" button it takes the price, the store name, and the barcode(this came from the view BEFORE "add price view") and sends to a server.
So as you can see I need data from different views.
I'm trying to understand what your scenario is. In the MVVMlight forum, you added the following context to this question:
"I have some data that needs to be passed to multiple screens and possibly back again."
For passing data between VMs, I would also - as Matt above - use the Messenger class of MVVMLight as long as it is "fire and forget". But it is the "possibly back again" comment that sounds tricky.
I can imagine some scenarios where this can be needed. Eg. a wizard interface. In such a case I would model the data that the wizard is responsible for collecting and then bind all Views to the same VM, representing that model object.
But that's just one case.
So maybe if you could provide a little more context, I would be happy to try and help.
Yes, you can do this, in as much as the code will work but there is a big potential issue you may run into in the future.
One of the strong arguments for using the MVVM pattern is that it makes it easier to write code that can be easily tested.
With you're above code you can't test ViewModel1 without also having ViewModelLocator and ViewModel2. May be that's not too much of a bad thing in and of itself but you've set a precedent that this type of strong coupling of classes is acceptable. What happens, in the future, when you
From a testing perspective you would probably benefit from being able to inject your dependencies. This means passing, to the constructor--typically, the external objects of information you need.
This could mean you have a constructor like this:
public ViewModel1(string vm2Name)
{
string name = vm2Name;
}
that you call like this:
var vm1 = new ViewModel1(ViewModelLocator.ViewModel2.name);
There are few other issues you may want to consider also.
You're also creating a new ViewModelLocator to access one of it's properties. You probably already have an instance of the locator defined at the application level. You're creating more work for yourself (and the processor) if you're newing up additional, unnecessary instances.
Do you really need a complete instance of ViewModel2 if all you need is the name? Avoid creating and passing more than you need to.
Update
If you capture the store in the first view/vm then why not pass that (ID &/or Name) to the second VM from the second view? The second VM can then send that to the server with the data captured in the second view.
Another approach may be to just use one viewmodel for both views. This may make your whole problem go away.
If you have properties in 1 view or view model that need to be accessed by a second (or additional) views or view models, I'd recommend creating a new class to store these shared properties and then injecting this class into each view model (or accessing it via the locator). See my answer here... Two views - one ViewModel
Here is some sample code still using the SimpleIoc
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IMyClass, MyClass>();
}
public IMyClass MyClassInstance
{
get{ return ServiceLocator.Current.GetInstance<IMyClass>();}
}
Here is a review of SimpleIOC - how to use MVVMLight SimpleIoc?
However, as I mentioned in my comments, I changed to use the Autofac container so that my supporting/shared classes could be injected into multiple view models. This way I did not need to instantiate the Locator to access the shared class. I believe this is a cleaner solution.
This is how I registered MyClass and ViewModels with the Autofac container-
var builder = new ContainerBuilder();
var myClass = new MyClass();
builder.RegisterInstance(myClass);
builder.RegisterType<ViewModel1>();
builder.RegisterType<ViewModel2>();
_container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(_container));
Then each ViewModel (ViewModel1, ViewModel2) that require an instance of MyClass just add that as a constructor parameter as I linked initially.
MyClass will implement PropertyChanged as necessary for its properties.
Ok, my shot at an answer for your original question first is: Yes, I think it is bad to access one VM from another VM, at least in the way it is done in the code example of this question. For the same reasons that Matt is getting at - maintainability and testability. By "newing up" another ViewModelLocator in this way you hardcode a dependency into your view model.
So one way to avoid that is to consider Dependency Injection. This will make your dependencies explicit while keeping things testable. Another option is to use the Messenger class of MVVMLight that you also mention.
In order to write maintainable and testable code in the context of MVVM, ViewModels should be as loosely coupled as possible. This is where the Messenger of MVVMLight can help. Here's a quote from Laurent on what Messenger class was intended for:
I use it where decoupled communication must take place. Typically I use it between VM and view, and between VM and VM. Strictly speaking you can use it in multiple places, but I always recommend people to be careful with it. It is a powerful tool, but because of the very loose coupling, it is easy to lose the overview on what you are doing. Use it where it makes sense, but don't replace all your events and commands with messages.
So, to answer the more specific scenario you mention, where one view pops up another "store selection" view and the latter must set the current store when returning back to the first view, this is one way to do it (the "Messenger way"):
1) On the first view, use EventToCommand from MVVMLight on the TextBox in the first view to bind the desired event (eg. GotFocus) to a command exposed by the view model. Could be eg. named OpenStoreSelectorCommand.
2) The OpenStoreSelectorCommand uses the Messenger to send a message, requesting that the Store Selector dialog should be opened. The StoreSelectorView (the pop-up view) subscribes to this message (registers with the Messenger for that type of message) and opens the dialog.
3) When the view closes with a new store selected, it uses the Messenger once again to publish a message that the current store has changed. The main view model subscribes to this message and can take whatever action it needs when it receives the message. Eg. update a CurrentStore property, which is bound to a field on the main view.
You may argue that this is a lot of messaging back and forth, but it keeps the view models and views decoupled and does not require a lot code.
That's one approach. That may be "old style" as Matt is hinting, but it will work, and is better than creating hard dependencies.
A service-based approach:
For a more service-based approach take a look at this recent MSDN Magazine article, written by the inventor of MVVMLight. It gives code examples of both approaches: The Messenger approach and a DialogService-based approach. It does not, however, go into details on how you get values back from a dialog window.
That issue is tackled, without relying on the Messenger, in this article. Note the IModalDialogService interface:
public interface IModalDialogService
{
void ShowDialog<TViewModel>(IModalWindow view, TViewModel viewModel, Action<TViewModel> onDialogClose);
void ShowDialog<TDialogViewModel>(IModalWindow view, TDialogViewModel viewModel);
}
The first overload has an Action delegate parameter that is attached as the event handler for the Close event of the dialog. The parameter TViewModel for the delegate is set as the DataContext of the dialog window. The end result is that the view model that caused the dialog to be shown initially, can access the view model of the (updated) dialog when the dialog closes.
I hope that helps you further!
OK, i am creating a web application. I am using MVC3. I have ViewModel for every view and also I have Data Model that supports viewModel and does the actuall CRUD operation in my sql table, while my viewModel validates and alters data as necessary.
Here is a question. The way I have been coding is
public class MyClassViewModel
{
public string member1{get;set;}
public int member2{get;set;}
public static GetAllMembers(MyClassViewModel obj, out string strErrMsg)
{
// code goes here, read operation
}
public static UpdateMyClass(MyClassViewModel obj, out string strErrMsg)
{
// code goes here, write operation.
}
}
Both My ViewModel and DataModels have been coded this way, My Controller on HttpPost just do something like this..
MyClassViewModel.UpdateMember(obj,out strErrMsg)
Since its mvc on every post it creates on a strongly typed view, a new object of my ViewModel, hence non static members are different and are not shared between sessions.
I am using Linq and therefore on each static method of my DataModel i use
var db = new MyApplicationDataContext()
to get my linq classes and work on them. This solves my open/close reader problems.
My question is, are there any issues regarding concurrency with this design? I know I might have problems in changing my data layer if it is not designed via interface, but I highly doubt that is necessary based on my application.
You are essentially using the factory design pattern. That's OK pattern to use for this; each static method has its own context, and that's OK too. You always have to worry about concurrency; however, the LINQ to SQL architecture has concurrency detection built in and throws a ChangeConflictException when a concurrent change has been made in reaction to this.
I would also highly recommend that you are disposing your contexts properly at the end of each static method call, because you could leave open connections to the database which can cause performance problems.
Also, another problem you may run into is interlinking data; you cannot link two objects together by reference that were created from different contexts. And in LINQ to SQL, there is no way to explicitly detach an object...
I have a viewmodel that can be use in the Controllers, View, and Core. The Core is a seperate project while the Controllers and View is in the Web Project. Where is the best location to put the ViewModel, is it in the Web project or in the Core, or do I need to created a seperate project for the View Model only?
I have a viewmodel that can be use in the Controllers, View, and Core.
No. You are not using it in the Core. Google "Separation of Concerns". The responsibility of the view model is to represent the Model (the Core project) in the view. It should not be used for anything else. I've written about view models here: http://blog.gauffin.org/2011/07/three-reasons-to-why-you-should-use-view-models/
It's the controllers responsibility to take everything from the Model (core
project) and create an appropriate view model.
Putting the view model somewhere so it can be used in the Core gives it more than one reason to change which will break the Single Responsibility Principle (one of the five SOLID principles). What it means is that several parts of your application will be affected by every change that you make and it will likely lead to small workarounds or quick fixes which will give you a maintenance nightmare in a year of so.
Update
Example using AutoMapper:
public class FlairController
{
public FlairController(IYourServiceOrRepository repos)
{
}
public ActionResult Details(int id)
{
SomeCoreObject entity = _repos.Get(id);
FlairViewModel model = new FlairViewModel();
Mapper.Map(entity, model);
return View(model);
}
}
Your example code (in the comment) is how the method would look like without a mapping framework.
Since ViewModels are specific to the Views, I would usually create a ViewModel folder under my UI project and keep it there.
I will create a seperate Service Layer ( another project) for bridging data between my ViewModels and Entity Models. My Controller Action methods call the service layer with the ViewModel object.
The view model is typically a wrapper around the model that has the UI formatted data. You should probably keep your model class in the Core project and the view model class in your web project.
The constructor for your View Model class can take an instance of your model class (and any other objects you need to populate your view) and generate the proper view data. For example, if you model has a DateTime object, then your view model could have a corresponding String property that contains the DateTime in the format you want to show.
I am attempting to write a custom membership class. It seems to work ok inhering the Membership class and providing functions for all the included required items (validate user, create user, delete user, isapproved, etc).
However, where I run into a problem is when I try to add properties or methods.
As all the other properties and methods are public override classes in a sealed class,
the additional properties do not show up.
Say for example (example only, not "real" code):
public sealed class Membership : MembershipProvider
{
public override string ApplicationName
{
get
{
return "myApp";
}
}
public string myValue { get;set;}
}
Now, I understand why myValue will not show up when I try to do Membership.myValue but Membership.ApplicationName will.
My question is, how to extend membership to show the custom items? Do I ditch Membership.xxx entirely and write a wrapper class? If so, how? I can find all the documentation in the world on how to create a custom membership class. I've got a working custom membership that works fine if I use all the available options only. I've got a custom roles provider and a custom config section to store everything and it's best friend.
What I don't have is an elegant solution.
I'd like the end result to be that I use one reference (such as Membership.xxx or myClass.xxxx) to reference all membership items + custom items.
Please provide examples of how to implement or links to appropriate items that will resolve the custom methods item.
Any time you reference the membership instance you will just have to cast it to your class type, that's all.
You can take a look at Extension Methods if you don't want to cast back and forth your instances
There are a lot of examples on how to "create your own model". Mark them with DataAnnotations. Scott Guthrie explains how to validate your model when using an ORM. What I don't find is when your model is actually coming in from an external DLL. How do you validate it?
Example:
/* Class coming in from an third-party DLL file. */
public class Person
{
public string Name{get;set;}
public int Age {get;set;}
}
The solution I am thinking of: Inherit the external class and then apply [MetadataType] to the inherited class.
[Metadata(typeof(Person2_Validation))]
public class Person2:Person{}
public class Person2_Validation
{
[Required,Stringlength(50,ErrorMessage="Name required"]
public string Name{get;set;}
[RegularExpression("([0-9]+)")]
public int Age
}
Is there a better way?
You could create a model and use a Mapper (like AutoMapper or EmitMapper or ValueInjecter) to map between your objects, and validate against the mapped model.
When you need to transfer the object back you can map between your model to the recieved model.
This is very similar to a ViewModel approach in ASP.NET MVC.
So it's something like this:
Class A (the class from the DLL)
Class B (your model)
You set all your annotations on B, and create whatever properties you need.
What you use is B. When you get something from the repository/source you map (copy all relevant values) A=>B and send it (let's say as a model in a View).
When you receive B back you validate it, and then map it the other way B=>A, and send it to the repository/service.
BTW: I would recommend using this approach even if model A was YOUR class.
Why use ViewModels instead of Domain Models in Views.
#Linkgoron answer is true. You are searching view model vs domain model. we need to think the model from dll is a domain model and map it to our own view model as we did even when dealing with our own repository/persistence. it is a best practice. don't worry about mapper, it will map automatically.
See this example:
http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx
See this #Nick DeVore answer why view model instead of domain model here
Why Two Classes, View Model and Domain Model?
and also
Bestpractice - Mixing View Model with Domain Model
Your issue could be one of the reason why :)