How do I get design-time view of a view-model first approach with IoC? - caliburn.micro

I have a MasterViewModel that contains other viewmodels.
public MasterViewModel()
{
User = new UserViewModel();
Search = new SearchViewModel();
}
When I in my MasterView add
<Window ...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:viewModels="clr-namespace:MyApp.ViewModels"
d:DataContext="{d:DesignInstance viewModels:MasterViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"
mc:Ignorable="d"
>
<ContentControl x:Name="User" />
<ContentControl x:Name="Search" />
I can see the content controls at design time.
Now, I would like to add the viewmodels via IoC like
public MainViewModel(UserViewModel user, SearchViewModel search, IEventAggregator events)
{
User = user;
Search = search;
}
but now the design time view doesn't work anymore. A blue squiggly for the d:DataContext.. says, "No parameterless constructor defined for this object".
How can I get it to work?

Well, the principle of IoC (inversion of control) is that dependency solving happens at run time and not at compile time.
As far as I know the designer does not support creating instances of view models with dependencies and solving them for itself. Thus there is the requirement for the empty constructor.
This would be the "hack" I'd use, if you insist on design-time support.
public ShellViewModel() : this(new UserViewModel(), new SearchViewModel())
{
}
public ShellViewModel(UserViewModel user, SearchViewModel search, IEventAggregator events)
{
User = user;
Search = search;
}
But as one can imagine this is going to get ugly while developing a larger application, if the UserViewModel gets dependencies. The new dependencies might have dependencies either, and so on... you see, you just run into the problem that IoC should actually solve.
But I think it is not too bad that your ContentControls remain empty. What you achieve with creating sub view models is decoupling the actual code. Why would you couple it once again in your designer? Because the corresponding views get decoupled through these ContentControls either.
The bigger the view model hierarchy gets, the bigger the content control hierarchy gets, which - in my opinion - blows up the amount of shown items in your designer unnecessarily.

The better solution in this case is to use DesignData instead of DesignInstance. The data needs to be created in Blend, but if you're using VS2012/VS2013 Blend comes with VS.
See these links for tutorials.
http://visitmix.com/labs/rosetta/eyesofblend/datatemplates/
http://msdn.microsoft.com/en-us/magazine/dn169081.aspx
What you want to do is create "sample data from class". This will insert data into a fictive instance of your class, as well as inserting lorem ipsum like text in your strings, several items in your lists etc.
It will keep those nasty empty constructors away, and you dont need to maintain test data in that empty constructor.

Related

Looking to avoid ViewBag usage in MVC 5 - suggestions?

So I have been googling how to remove any and all usage of ViewBags in favour of something more elegant and effective. Unfortunately virtually all of the information I have come across is for prior versions of MVC, and I have yet to find something that both works and is really effective.
One of my primary objective is to be able to populate both the page and the layout at the same time, so that I can add a page title to both the <h2> as well as the <title>. I also want to be able to, if needed, to supply the first paragraph of the body content, which is drawn from the database as a separate column, to the meta-description (this is a special case where all first paragraphs are their own separate entry in the row in the db, purely for the purpose of also acting as the meta-description).
I have run across something that I believe will meet my needs, but I cannot seem to properly implement the fifth code block:
Now create the view base class. You need to create two versions to
have support for typed views.
public class ViewBaseWithLayoutModel : WebViewPage{
public LayoutViewModel LayoutModel {
get { return (LayoutViewModel)ViewBag.LayoutModel; }
}
}
public class ViewBaseWithLayoutModel<T> : WebViewPage<T>{
public LayoutViewModel LayoutModel {
get { return (LayoutViewModel)ViewBag.LayoutModel; }
}
}
Specifically, it is the “create the view base class” that has me tied up in knots -- are they talking about an entirely new section in the project, similar to the Views, Controllers, Models, Extensions, Validators, etc., such that the namespace would be namespace Project.ViewBase {?
And if I can put the fifth code block straight beside another controller like BaseController (inside the Project.Controllers namespace but below the BaseController class in that file), why do both classes throw the errors,
'ViewBaseWithLayoutModel' does not implement inherited abstract member 'WebPageExecutingBase.Execute()'
As well, the sixth code block references
<pages pageBaseType="Namespace.To.ViewBaseWithLayoutModel">
So in the above case would it be 'Project.Controllers.ViewBaseWithLayout'?
Any help would be greatly appreciated.

Binding Model properties directly in View

I've found this text in Prism documentation. I'm starting on MVVM and I'm at lost. Can (should) I bind model properties in the view or I must create a viewmodel with a proxy property for every property in the model?
The model classes typically provide
property and collection change
notification events through the
INotifyPropertyChanged and
INotifyCollectionChanged interfaces.
This allows them to be easily data
bound in the view. Model classes that
represent collections of objects
typically derive from the
ObservableCollection class.
EDIT: Here is some extra info to help. I'm building a personal project from the ground up (so I'm designing the models too), this is the first time that I use MVVM and I want to learn properly.
My model is very hieraquical, having classes with list of more class with more list inside, building a complex tree of information. I was trying the "standard" MVVM approach, build the model with POCO and no notifications, and using List. Then building the ViewModel with proper notifications and using ObservableCollections.
The problem is, the way it is going, I'm almost reconstructing my whole model as a ViewModel AND having to keep the data synched between the to (the ObservableCollection to the List). Then I read that on the Prism docs and wondered if I should have all that trouble or just create a root ViewModel for logic and bind all the rest to the model itself.
It depends really, if your model already implements INotifyPropertyChanged and/or IError info you might want to bind right to the model property. However if you want to do special validation and other stuff that the model knows nothing about you add the property wrappers in your view model.
This article gives a good example of a hybrid: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Often my MV properties look like this and thats quite normal:
public string Symbol
{
get { return Model.Symbol; }
set { Model.Symbol = value; this.NotifyOfPropertyChange(() => this.Symbol); }
}
I often do NOT implement INotifyPropertyChanged in the model and thus often I have to write the wrappers.
EDIT: In response to your additional information: It can be a bit tricky to to keep the collections and lists in sync. In your case what I would do is to create a view model for each model class, but NOT wrap all the properties just access them like this: {Bindng Customer.Name}. But of course you have to create a wrapper for the collections which contain view models. The Prism documentation is, as they say themselves, just guidance, if your scenario needs a different approach then this is fine.
Take a look at this code. I only wrap the collections and the properties I will access through the model. This gives you the best of both worlds. Then IF you need a special property that does not belong into you model you can add it to the view model (see the CustomerViewModel), or if you need special notification for a certain properties.
class CompanyViewModel{
public CopanyViewModel(Company c){
foreach(var customer in c.Customers)
Customers.Add(new CustomerViewModel(customer);
}
public Company Company {get;set;}
public ObservableCollection<CustomerViewModel> Customers {get;set;}
}
class CustomerViewModel{
public CustomerViewModel(Customer c){
Customer = c;
}
public Customer Customer {get;set;}
public Brush CustomerBackground{
get{
if(Customer.Active)
return Brush.Greeen;
else
return Brush.Red;
}
}
}
(This code might not work, I just typed it in here.)
Now, if you need changed notification for all models and all properties you have to either implement it in you model or in wrap all properties in a view model.

Adding and removing items dynamically in one View with Entity Framework and MVC

I've been at this same question in different forms now for a while (see e.g. Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and it's still bugging me, so I thought I'd put it a little more generically:
I feel this can't be a very unusual problem:
You have an entity object (using Entity Framework), say User. The User has some simple properties such as FirstName, LastName, etc. But it also has some object property lists, take the proverbial example Emails, to make this simple. Email is often designed as a list of objects so that you can add to that object properties like Address and Type (Home, Work, etc). I'm using this as an example to keep it generic, but it could be anything, the point is, you want the user to be able to add an arbitrary number of these items. You should also be able to delete items (old address, or whatever).
Now, in a normal web page you would expect to be able to add these items in the same View. But MVC as it seems designed only makes it easy to do this if you call up an entirely new View just to add the address. (In the template for an Index View you get the "Create New" link e.g.).
I've come across a couple of examples that do something close to what I mean here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
and
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
The problem is, although the sample projects on these sites work fine, with mock model objects, and simply lists (not an object with a child list), it's a different thing if you actually want to do something with the posted information - in my case save to database through the Entity Framework model. To adapt these cases to that, all of a sudden I'm in a maze of intricate and definitely not DRY code... Juggling objects with AutoMapper and whatnot, and the Entity Framework won't let you save and so on (see above link if you're interested in the details).
What I want to get at is, is it really possible that this is such an uncommon thing to want to do? Update a child collection in the same View as the parent object (such as the email addresses in this case)? It seems to me it can't be uncommon at all, and there must be a standard way of handling this sort of scenario, and I'm just missing it (and no one here so far has been able to point me to a straighforward solution, perhaps because I made it too abstract with my own application examples).
So if there is a simple solution to what should in my view be a simple problem (since the design is so common), please tell me.
Have you tried updating the project at your link to Steven Anderson's blog to bind to a complex object? Create a class in models called Sack and give it a single property and see if you can get it to work.
public class Sack
{
public IEnumberable<Gift> Gifts { get; set; }
}
It only took me a minute to get it up and running as I think you intend. The improvement I would have made next would be to add an HtmlHelper extension that is essentially the same as Html.EditorFor(m => m.SomeProperty), only call it something more meaningful and have it interface with the prefix scope extensions provided in the project.
public static class HtmlExtensions
{
public static IHtmlString CollectionEditorFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if (/* type of expression value is not a collection */) throw new FailureToFollowTheRulesException("id10t");
// your implementation
}
}

NHProf generates 'this statement executed from the view' warning when I pass a ViewModel object to my ASP.NET MVC View page

I just noticed that on one page of my site, where I pass a ViewModel to my View page, NHProf is giving the following warning:
This statement executed from the view, which can result in bad performance and/or brittle behaviour.
It then links to this page: http://nhprof.com/Learn/Alerts/QueriesFromViews
My ViewModel consists of just 2 properties:
public IEnumerable<Photo> Photos { get; set; }
public Photo SelectedPhoto { get; set; }
I assign the photos to this ViewModel within my Controller as follows:
PhotoViewModel myViewModel = new PhotoViewModel();
myViewModel.Photos = entity.Photos;
My View obviously inherits this type, and aside from outputting a header (which makes use of the SelectedPhoto object), it just loops through each of the Photos rendering some content for each of them.
NHProf shows the 'problem' query as being where it retrieves the collection of Photos that I'm looping through in my view, though I'm not explicitly telling it to go off and get those records from within my view - I've passed those records within the Photos property of my ViewModel.
I have other pages where I don't need to pass a ViewModel and I simply pass IEnumerable<Photo> to the View, and then render the markup exactly the same as I do in the problem view, and NHProf gives no warnings (as there shouldn't be) in that scenario.
I'm thinking maybe it's related to Lazy Loading, and because my collection is part of a ViewModel, when I go to loop through the Photos property within the ViewModel type, it goes to get those records at that point?
Does anyone have any idea what is happening here? The site functions perfectly, but NHProf just sees that it's doing something from where it shouldn't be doing it?!
You haven't shown how your Photos collection is being populated, but I assume it's as simple as viewModel.Photos = entity.Photos. If that's correct (or something similar), then you're just assigning the lazy-loaded entity collection to your view model.
There are several ways to tackle this, but they're all essentially the same: you need to trigger the loading of your collection before you populate your view model. The easiest way to do it is to just stick a .ToArray() or equivalent onto the collection you're assigning; that'll force a fetch.
You are right. It is related to Lazy loading. Try to load Photos eagerly. And check their relations. Maybe they have some with eager loading, you don't need, or you are trying to use associated entity in your view.

ASP.NET: Custom dynamically populated site map (SiteMapProvider)

I'm trying to write my first very own SiteMapProvider subclass. It is meant to be populated dynamically using a bunch of different database lookups, much like all of the examples I've found on the web.
However, there are a whole bunch of things that are quite unclear to me. Here are my two first questions:
Why is StaticSiteMapProvider used in virtually everyone's project instead of SiteMapProvider? Since the class contains the name "static", I'm getting the impression that it's not as...well, dynamic as I want it.
Can someone provide me with a super-minimalistic SiteMapProvider subclass which populates the map using only static data, i.e. no database access, etc.?
SiteMapProvider can be tottaly dynamic. For example it can make dynamic lookup just for nodes. In contrast with StaticSiteMapProvider you should know whole structure. So this for you to decide what to choose.
You can look at the XmlSiteMapProvider, this is good example of "static" map provider.
public class CoolMapProvider : StaticSiteMapProvider
{
public override SiteMapNode BuildSiteMap()
{
var root = new SiteMapNode(this, "test", "~/test.aspx");
base.AddNode(root, null);
base.AddNode(new SiteMapNode(this, "test-child", "~/test_child.aspx"), root);
return root;
}
}
I did not checked this, but should work.

Resources