I'm using WPF, MVVM and Entity Framework in my current project.
To keep things simple, let's say I have a viewmodel for CRUD operations towards a list of materials (Solid woods).
My ViewModel's EF context (WTContext) is initialized through property injection, for instance:
SolidWoods_VM newView = new SolidWoods_VM();
newView.Context = new WTContext(SettingsManager.Instance.GetConnectionString());
This way I'm able to test this ViewModel:
SolidWoods_VM swVM = new SolidWoods_VM();
swVM.Context = new FakeWTContext();
Imagine that during a insert operation something goes wrong and the WTContext.SaveChanges() fails.
What is the best way to refresh the ViewModels context?
Create a new bool property in the viewmodel named ForTestingPurposes, and when the SaveChanges method fails:
try
{
Context.SaveChanges();
}
catch
{
if (!ForTestingPurposes)
{
Context = new WTContext(SettingsManager.Instance.GetConnectionString());
}
}
Send a message to the mainviewmodel for context reloading (through mediator pattern):
Mediator.Instance.NotifyColleagues<SolidWoods_VM>(MediatorMessages.NeedToUpdateMyContext, this);
(Yet, this way I'd still need the bool property)
3.A more elegant solution, without aditional properties, provided for you guys :)
Why not abstract the methods/properties you need on your data context onto an interface and then have an implementation of that that handles the exception.
//WARNING: written in SO window
public interface IDataSource
{
void SaveChanges();
//... and anything else you need ...
}
public class RealDataSource : IDataSource
{
private WTContext _context;
public void SaveChanges()
{
try { _context.SaveChanges(); }
catch
{
_context = new WTContext(/*...*/);
}
}
}
This way you can still implement a fake/mock data source but your view model class doesn't need to know anything about how the data is actually retrieved.
My opinion is that your best bet would be the message.
You need a way to indicate that the save went wrong, and it might not serve all consumers of the class to have the context regenerated. If you're binding to your VM in there, for example, resetting the context might have other UI consequences.
Related
Should it be like this
public class DataAccess
{
MyDbContext ctx;
public DataAccess()
{
ctx = new MyDbContext();
}
public List<entity> GetAll()
{
return ctx.entities.ToList();
}
}
or this
public List<entity> GetAll()
{
using (var ctx = new MyDbContext())
{
return ctx.entities.ToList();
}
}
Thanks a lot and if there is a problem in my questions, please inform me so that I may improve it.
The optimal lifetime of a DbContext depends on your requirements and may vary from case to case but in general you should prefer short-lives contexts (the second code snippet in your sample code):
Entity Framework’s contexts are meant to be used as short-lived instances in order to provide the most optimal performance experience ...
https://msdn.microsoft.com/en-gb/data/hh949853.aspx#9
if i have a viewmodel for adding new item and another viewmodel for displaying all or filtered items (the second viewmodel's view must always reflect any changes in the collection source), should the change be communicated from viewmodel to viewmodel directly, or viewmodel to repository to the second viewmodel?
The first view model could for example add the new item to an ObservableCollection of the second view model that the view binds to. So it should add the new item to the database using the respository and also add the new entity object to the source collection of the second view model one way or another.
Short version:
If I have ViewModel, containing its Model object and exposing its properties, how do I get the model "back" after it has been edited? If the Model-inside-ViewModel is public, it violates encapsulation, and if it is private, I cannot get it (right?).
Longer version:
I am implementing a part of an application which displays collections of objects. Let's say the objects are of type Gizmo, which is declared in the Model layer, and simply holds properties and handle its own serialization/deserialization.
In the Model layer, I have a Repository<T> class, which I use to handle collections of MasterGizmo and DetailGizmo. One of the properties of this repository class is an IEnumerable<T> Items { get; } where T will be some of the Gizmo subtype.
Now since Gizmo doesn't implement INPC, I have created the following classes in ViewModel layer:
GizmoViewModel, which wraps every public property of a Gizmo so that setting any property raises PropertyChanged accordingly;
[**] RepositoryViewModel<T>, which has an ObservableCollection<GizmoViewModel> whose CollectionChanged is listened to by a method that handles Adds, Removes and Updates to the repository.
Notice that the Model layer has a "Repository of Models", while the ViewModel layer has a "ViewModel with an ObservableCollection of ViewModels".
The doubt is related to the [**] part above. My RepositoryViewModel.CollectionChangedHandler method is as follows:
void CollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var added in e.NewItems)
{
var gvm = added as GizmoViewModel;
if (gvm != null)
{
//// IS ANY OF THE ALTERNATIVES BELOW THE RIGHT ONE?
// Gizmo g = gvm.RetrieveModel(); ?? proper getter ??
// Gizmo g = GetModelFromViewModel(gvm); ?? external getter ??
// Gizmo g = gvm.Model; ?? public model property ??
_gizmo_repository.Add(g);
}
}
break;
....
Besides that, if anyone can detect any MVVM smell here, I'll be happy to know.
We can deal with our Models even outside the View and ViewModel layers, so leaving the model publicly accessible from ViewModel is I believe acceptable.
Let say you are creating the Models in "DataLayer" you can pass the instance of the Model to the ViewModel. To illustrate my point:
///Models ////////////////////////////
public interface IGizmo{}
public class Gizmo:IGizmo{}
public class SuperGizmo : IGizmo {}
public class SuperDuperGizmo : IGizmo { }
//////////////////////////////////////
public interface IGizmoViewModel<out T>
{
T GetModel();
}
public abstract class GizmoViewModelBase : IGizmoViewModel<IGizmo>
{
protected GizmoViewModelBase(IGizmo model)
{
_Model = model;
}
private readonly IGizmo _Model;
public IGizmo GetModel()
{
return _Model;
}
}
public class GizmoViewModel : GizmoViewModelBase
{
public GizmoViewModel(Gizmo model)
: base(model) { }
}
public class SuperDuperGizmoViewModel : GizmoViewModelBase
{
public SuperDuperGizmoViewModel(SuperDuperGizmo model)
: base(model){}
}
Your repository of Models will be updated on whatever updates it get from the ViewModel as long as you passed the same instance. So there is no need to have a repository of ViewModels to get the updates.
Reading your code, I think there is something of a mixup regarding your ViewModel and Model separation.
So, as I understand it, when your ObservableCollection of GizmoViewModel's changes, you are trying to add the Gizmo instance of the new item back to your Model?
I would approach this differently. You should create your Gizmo instances inside your Model layer, and when you do this you should add it to the Repository.
Otherwise, you haven't provided enough information - or rather, you have provided too much but it is the wrong sort of information. You need to describe the situation in which you want to do this, where these GizmoViewModels are created, etc.
From what I can see here, your GizmoViewModel has a dependency to your Repository<T>, so why not pass in the repository when you create your view model?
public class GizmoViewModel
{
private IRepository<Gizmo> _Repo;
//Underlying model (Doesn't implement INotifyPropertyChanged)
private Gizmo _Model;
//Wrapping properties
public int MyProperty
{
get { return _Model.Property; }
set
{
_Model.Property = value;
NotifyOfPropertyChange();
}
}
...
public GizmoViewModel(IRepository<Gizmo> repo)
{
_Repo = repo;
}
public void AddToRepo()
{
_Repo.Add(_Model);
}
...
It would be even better if these methods are inside the RepositoryViewModel base class. You can really go crazy with inheritance here. Perhaps something like this:
var gvm = added as IRepositoryViewModel;
if (gvm != null)
gvm.AddToRepo();
You can then simply call AddToRepo when you need to add the view model's underlying model to the repository.
Perhaps not the most elegant solution, however if encapsulation is what's worrying you, then you need to ensure that your dependencies are properly managed.
"If the Model-inside-ViewModel is public, it violates encapsulation"
Your assertion above is completely wrong and is killing your code.
By setting the Model property in ViewModel as private, you are forced to repeat your self ( code smells ), as you will need to define in your ViewModel, the same properties as you did for your Model, effectively transforming it into a Model class that mimics the Model it is supposed to expose to the View.
In MVVM the ViewModel role is to provide the View with all the presentation data and logic that it needs and for sure the Model is fundamental part of this data, by hidding it from the View you are killing MVVM.
I 'm fairly new to Prism and I 'm currently re-writing one of our existing applications using Prism as a proof of concept project.
The application uses MVVM with a ViewModel first approach: our ViewModel is resolved by the container, and an IViewResolver service figures out what view it should be wired up to (using name conventions amongst other things).
The code (to add a view to a tab control) at the moment looks something like this:
var vm = (get ViewModel from somewhere)
IRegion reg = _regionManager.Regions["MainRegion"];
var vw = _viewResolver.FromViewModel(vm); // Spins up a view and sets its DataContext
reg.Add(vw);
reg.Activate(vw);
This all works fine, however I 'd really like to use the Prism navigation framework to do all this stuff for me so that I can do something like this:
_regionManager.RequestNavigate(
"MainRegion",
new Uri("NameOfMyViewModel", UriKind.Relative)
);
and have Prism spin up the ViewModel + View, set up the DataContext and insert the view into the region.
I 've had some success by creating DataTemplates referencing the ViewModel types, e.g.:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Module01">
<DataTemplate DataType="{x:Type local:TestViewModel}">
<local:TestView />
</DataTemplate>
</ResourceDictionary>
...and have the module add the relevant resource dictionary into the applications resources when the module is initialized, but that seems a bit rubbish.
Is there a way to effectively take over view creation from Prism, so that when RequestNavigate is called I can look at the supplied Uri and spin up the view / viewmodel based on that? There’s an overload of RegionManager.RegisterViewWithRegion that takes a delegate that allows you to supply a view yourself, and I guess I’m after something like that.
I think I might need to supply my own IRegionBehaviorFactory, but am unsure what's involved (or even if I am on the right path!).
Any help appreciated!
--
note: Originally posted over at the prism codeplex site
Sure you can do that. I 've found that Prism v4 is really extensible, if only you know where to plug in.
In this case, you want your own custom implementation of IRegionNavigationContentLoader.
Here's how to set things up in your bootstrapper (the example is from a subclass of UnityBootstrapper from one of my own projects):
protected override void ConfigureContainer()
{
// IMPORTANT: Due to the inner workings of UnityBootstrapper, accessing
// ServiceLocator.Current here will throw an exception!
// If you want access to IServiceLocator, resolve it from the container directly.
base.ConfigureContainer();
// Set up our own content loader, passing it a reference to the service locator
// (it will need this to resolve ViewModels from the container automatically)
this.Container.RegisterInstance<IRegionNavigationContentLoader>(
new ViewModelContentLoader(this.Container.Resolve<IServiceLocator>()));
}
The ViewModelContentLoader itself derives from RegionNavigationContentLoader to reuse code, and will look something like this:
public class ViewModelContentLoader : RegionNavigationContentLoader
{
private readonly IServiceLocator serviceLocator;
public ViewModelContentLoader(IServiceLocator serviceLocator)
: base(serviceLocator)
{
this.serviceLocator = serviceLocator;
}
// THIS IS CALLED WHEN A NEW VIEW NEEDS TO BE CREATED
// TO SATISFY A NAVIGATION REQUEST
protected override object CreateNewRegionItem(string candidateTargetContract)
{
// candidateTargetContract is e.g. "NameOfMyViewModel"
// Just a suggestion, plug in your own resolution code as you see fit
var viewModelType = this.GetTypeFromName(candidateTargetContract);
var viewModel = this.serviceLocator.GetInstance(viewModelType);
// get ref to viewResolver somehow -- perhaps from the container?
var view = _viewResolver.FromViewModel(vm);
return view;
}
// THIS IS CALLED TO DETERMINE IF THERE IS ANY EXISTING VIEW
// THAT CAN SATISFY A NAVIGATION REQUEST
protected override IEnumerable<object>
GetCandidatesFromRegion(IRegion region, string candidateNavigationContract)
{
if (region == null) {
throw new ArgumentNullException("region");
}
// Just a suggestion, plug in your own resolution code as you see fit
var viewModelType = this.GetTypeFromName(candidateNavigationContract);
return region.Views.Where(v =>
ViewHasDataContract((FrameworkElement)v, viewModelType) ||
string.Equals(v.GetType().Name, candidateNavigationContract, StringComparison.Ordinal) ||
string.Equals(v.GetType().FullName, candidateNavigationContract, StringComparison.Ordinal));
}
// USED IN MY IMPLEMENTATION OF GetCandidatesFromRegion
private static bool
ViewHasDataContract(FrameworkElement view, Type viewModelType)
{
var dataContextType = view.DataContext.GetType();
return viewModelType.IsInterface
? dataContextType.Implements(viewModelType)
: dataContextType == viewModelType
|| dataContextType.GetAncestors().Any(t => t == viewModelType);
}
// USED TO MAP STRINGS OF VIEWMODEL TYPE NAMES TO ACTUAL TYPES
private Type GetTypeFromName(string typeName)
{
// here you need to map the string type to a Type object, e.g.
// "NameOfMyViewModel" => typeof(NameOfMyViewModel)
return typeof(NameOfMyViewModel); // hardcoded for simplicity
}
}
To stop some confusion about "ViewModel first approach":
You use more a "controller approach", but no "ViewModel first approach". A "ViewModel first approach" is, when you inject your View in your ViewModel, but you wire up both, your ViewModel and View, through a third party component (a controller), what by the way is the (I dont want to say "best", but) most loosely coupled approach.
But to answer your Question:
A possible solution is to write an Extension for the Prism RegionManager that does exactly what you have described above:
public static class RegionManagerExtensions
{
public static void AddToRegion<TViewModel>(
this IRegionManager regionManager, string region)
{
var viewModel = ServiceLocator.Current.GetInstance<TViewModel>();
FrameworkElement view;
// Get View depending on your conventions
if (view == null) throw new NullReferenceException("View not found.");
view.DataContext = viewModel;
regionManager.AddToRegion(region, view);
regionManager.Regions[region].Activate(view);
}
}
then you can call this method like this:
regionManager.AddToRegion<IMyViewModel>("MyRegion");
I have a page where you basically select a set of options (configuration), and then you go to a next page, where you do some stuff
Using the MVVM Light toolkit, I have a viewmodel that binds to the view of the first page. when the user hits a button, it redirects to another view, which would be the 2nd page
i.e.:
Page2Command = new DelegateCommand((obj) =>
Messenger.Default.Send<Uri>(new Uri("/DoStuffView.xaml", UriKind.Relative),
Common.CommonResources.GoToDoStuffRequest)) });
The problem is, the viewmodel for the 2nd view (the way that I see it) has a couple of parameters in the constructor, which are basically the dependencies on the configuration that was set on the first page.
i.e. :
public DoStuffViewModel(ICollection<Note> availableNotes, SoundMappers soundType)
{
}
The problem lies here.. How can I instantiate the viewmodel with this data that was dynamically selected by the user on the 1st page?.
I can't use the ViewModelLocator pattern that MVVM light provides, since those viewmodels don't have any dependencies, they are just by themselves (or they can retrieve data from a db, file or whatever, but they don't have any dynamic input data). I could do it through the view's constructor, instantiate there the viewmodel, and assign to the view's DataSource the newly created viewmodel, but I think that's not very nice to do.
suggestions?
As I see you send messsage using Messenger class so you are familiar with messaging in MVVM light. You have to define your own message type that should accept your parameters from page 1:
public class Page2ViewModelCreateMessage : MessageBase
{
public ICollection<Note> AvailableNotes{get;set;}
public SoundMappers SoundType{get;set;}
public Page2ViewModelCreateMessage ()
{
}
public Page2ViewModelCreateMessage(ICollection<Note> availableNotes, SoundMappers soundType)
{
this.AvailableNotes = availableNotes;
this.SoundType = soundType;
}
}
You have to send an Page2ViewModelCreateMessage instance with you parameters and send it on navigating:
var message = new Page2ViewModelCreateMessage(myAvailableNotes, mySoundType)
Messenger.Default.Send(message);
On Page2 you have to register for recieving message of type Page2ViewModelCreateMessage:
Messenger.Default.Register<Page2ViewModelCreateMessage>(this, OnPage2ViewModelCreateMessage);
..
public void OnPage2ViewModelCreateMessage(Page2ViewModelCreateMessage message)
{
var page2ViewModel = new Page2ViewModel(messsage.AvailableNotes, message.SoundType);
}
As you can see I have replace your DoStuffViewModel with Page2ViewModel to be more clear.
I hope this will help you.
NOTE:I dont guarantee that code will work as its written in notepad.
The way I do this is to have a central controller class that the ViewModels all know about, via an interface. I then set state into this before having the phone perform the navigation for me. Each ViewModel then interrogates this central class for the state it needs.
There are a number of benefits to this for me:
It allows me to have non-static ViewModels.
I can use Ninject to inject the concrete implementation of the controller class and have it scoped as a singleton.
Most importantly, when tombstoning, I only need to grab the current ViewModel and the controller class.
I ran into a problem with messaging where my ViewModel was the registered listener, because I was View First and not ViewModel First, I was forced to use static ViewModel references. Otherwise the ViewModel wasn't created in time to receive the message.
I use the controller class in conjunction with messages (it is basically the recipient of all messages around the UI) so in future if I refactor, I don't need to change much, just the recipients of the messages.
Come to think of it, the controller class is also my navigation sink - as I have some custom navigation code that skips back paging on certain pages etc.
Here's an example of my current set up:
public interface IController
{
Foo SelectedFoo { get; }
}
public class ViewModel
{
private IController _controller;
public ViewModel(IController controller)
{
_controller = controller;
}
private void LoadData()
{
// Using selected foo, we load the bars.
var bars = LoadBars(_controller.SelectedFoo);
}
}
You could use PhoneApplicationService dictionary to save data you need when navigation from first event, and parse it when you navigateTo second page. you can also use that data in your ViewModels.
Something like this:
PhoneApplicationService.Current.State["DatatFromFirstPage"] = data;
and when navigating to second page:
if (PhoneApplicationService.Current.State.ContainsKey("DatatFromFirstPage"))
{
var dataUsedOnSeconPage= PhoneApplicationService.Current.State["DatatFromFirstPage"];
}
you can use this data globally in entire app
I am implementing a WPF based application using MVVMfor the UI.
I have a ViewModel that wraps each editable Model that can be edited. The VM contains all the logic for handling error notifications, "is dirty" management and so forth ..
This design supports well CRUD schenarios for simple domain Model objects that are anemic, that is, do not contain any logic.
Now, I am facing a more tricky problem cause I have a domain Model that contains logic and that logic can change the internal state of the domain Model.
Do someone have already faced this scenario ? If so, do you have some advices to handle this correctly ?
Riana
Here is how I usually deal with it:
The ViewModel layer is made of types that belong to this layer, meaning I don't ever directly use my business objects inside of a ViewModel. I map my business objects to ViewModel objects that may or may not be the exact same shape minus the behaviors. It can be argued that this violates Don't Repeat Yourself, but doing so allows you to adhere to the Single Responsibility Principle. In my opinion, SRP should usually trump DRY. The ViewModel exists to serve the view, and the model exists to serve business rules / behavior.
I create a facade/service layer that takes and returns ViewModels as arguments, but maps the ViewModels to-and-from their corresponding business object versions. This, way the non-anemic objects won't impose non view logic on the ViewModel
The dependencies would look like this:
ViewModel <--> Facade/ServiceLayer --> Business Objects
I think it is important to keep this in mind if you want to unleash the full potential of MVVM: The ViewModel is the model/abstraction of the view, not the model presented to the view.
Try using Command pattern. Your screen should be design not to edit an entity but to perform an action (command) on an entity. If you follow that principle when designing your screens, your ViewModel will have properties that should be mapped to a command object. Then, the command will be send to an (remote) facade of the domain model.
ViewModels for displaying the data could be mapped directly to the database (bypassing the domain model altogether) so that you don't need to put nasty getters in the domain model classes.
If the domain model is non-anemic, you will need to use events to communicate internal changes in the Model back to the ViewModel. That way you don't have to worry about keeping track of what operations could potentially make your VM out-of-sync with the model.
Here's a simple example:
First, a sample model:
public class NonAnemicModel
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
OnNameChanged(EventArgs.Empty);
}
}
public event EventHandler NameChanged;
protected virtual void OnNameChanged(EventArgs e)
{
if (NameChanged != null)
NameChanged(this, e);
}
public void PerformNameCalculation(int chars)
{
//example of a complex logic that inadvertently changes the name
this.Name = new String('Z', chars); //makes a name of Z's
}
}
And here's a sample ViewModel:
public class MyViewModel : INotifyPropertyChanged
{
private NonAnemicModel _model;
public NonAnemicModel Model
{
get { return _model; }
set
{
_model = value;
_model.NameChanged += (sender, args) => NotifyPropertyChanged("UserName");
}
}
public string UserName
{
get { return this.Model.Name; }
set { this.Model.Name = value; }
}
//this command would call out to the PerformNameCalculation method on the Model.
public ICommand PerformNameCalculation { get; private set; }
}
Notice that the PropertyChanged event is raised when the Name on the model changes. That way, regardless of whether the UserName setter was used, or the PerformNameCalculation command was used, the ViewModel stays in sync. The big downside to this is that you have to add many more events to your Model, but I've found that having these events in place is usually very helpful in the long run. Just be careful about memory leaks with events!