I have created a Base-Controller from which all the controllers inherit. Currently this controller fills some data (which I use in most views) into the ViewData-Container like this:
protected override void Initialize(System.Web.Routing.RequestContext rc)
{
base.Initialize(rc);
ViewData["cms_configuration"] = new CmsConfiguration();
// etc.
}
I don't like the fact that I need to read (and cast) from ViewData within the views. I'd like to introduce a BaseViewModel from which all ViewModels will inherit from, defining the properties instead of using ViewData. But how or where can I populate the BaseViewModel within the BaseController? Is there some kind of hook? Or do I simply need to define a function in BaseController, which I call in the Child-Controller?
E.g. (Child-Controller:
//{...}
base.PopulateBaseView(MyView);
return View(MyView);
Thx for any tipps.
sl3dg3
You could optionally use ActionFilters to do stuff like this:
Check out this article:
http://www.asp.net/mvc/tutorials/understanding-action-filters-cs
It explains ActionFilters nicely. That way you can separate different populate-logic into different filters, and turn them on and off as you please.
Related
My project is build on MVVM. Currently I have a list where i can select an object and add them to another list. What I want to make is a new window where this list is shown (the list with objects that are added) and edit that list in the new window (delte an item from that list).
How should I pass the data (selected object) to another window and be able to update them there?
I currently have it working in one view. In some related questions they advice MVVM light so I tried looking for that, from what I red mvvm light is mostly used to replace the notify property change. Should I use mvvm light or are there some specific patterns I could use?
Both windows will be open at the same time.
If you want to share your ViewModel between windows, you can use a ViewModelLocator. It is not specific to MvvmLight, it just creates one for you with its project template. You can implement it yourself, it is basically a container for your ViewModels. You can look here for the implementation details.
I've got to say that I'm not sure that these are the best approaches and if they are common, it's just what me and my colleagues were using in a WinRT application, so I'll be really glad if someone comes up with something better (both of these are not that clean).
I can think of two ways to pass data (without persisting it)
Pass parameters on page navigation
Have common shared class (Static or singleton class with some common data accessible from all ViewModels)
For passing on navigation:
I have this method in my Navigation service class:
public virtual void NavigateTo(Type sourcePageType, object parameter)
{
((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
}
and I use it like this in navigation commands:
Navigation.NavigateTo(typeof(PageType), someParameters);
Then you could get the values in the code behind of the navigated page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var receivedParameter = e.Parameter as TheTypeOfThePassedParameter;
}
And from there to pass them to the ViewModel, maybe there is an option to pass this without code in the code behind but I've not tried this.
Having shared class:
This is pretty much straightforward just have static class or a singleton with the desired fields.
I have MVC 5 project where I have a bunch of views, and I've set it in the web.config in the folder to have them all inherit from a custom class which inherits from WebViewPage so that I can add in properties/methods that all views can use.
public abstract class SCView<T> : WebViewPage<T>
{
}
I happen to have a little bit of presentation logic (yes, I know, not good - but I have to do this, for a lot of different reasons). The logic is simple enough, and goes as follows:
if([condition])
{
Html.RenderAction("DoThis", "Page", new { Area = "Common", model = Model, viewname = "TitlePanel" });
}
else if([another condition])
{
Html.Partial("/Areas/Common/Views/Media/TitlePanelEdit.cshtml", Model) *#
}
Essentially, if the first condition is met, I need to display a certain controller action - else, render a different partial view.
I would like to not do this in every view - so I was hoping to incorporate this logic in the CustomView class somehow. However, I'm finding that the Html helper methods cannot be used directly in this class - if I was inside a controller, this would be easier, obviously. Is there anyway I can put this so that this logic can be centralized?
Maybe I am missing something in your question, however, it seems to me that you just need to standardise your calls.
either pick
#Html.Action
#Html.Partial
Or
#Html.RenderAction
#Html.RenderPartial
Rather than mixing the types, then your viewbase logic will be able to return the same type, either void in the case of Render... as those output to the stream, or an mvchtmlstring if you go with the non render versions
On the site I'm working on, there are users with different permissions on the site.
Given the schedule ID and employee ID that we're currently looking at, we can get their role-specific permissions.
Right now, our BaseModel has a property that properly accesses the DB and grabs this info.
For all views that pass a model to the view, everything runs fine.
The problem lies in Controller Methods where no model is passed. In a few views, all they're supplied is a few ViewBag entries, and work fine.
However, I /need/ the CurrentPermissions property in those pages nonetheless, for the layout. Whether or not the permissions have one boolean value set true/false, something may/may not be displayed/populated.
So, my option seem to be:
Somehow throw my CurrentPermissions into a ViewBag entry for all views, and access them through that instead of the base model.
I'm not sure how to do this. I've seen people using OnActionExecuting, but that fails since my connection to TransactionManager is not yet set up at that point.
Somehow throw just the BaseModel into those views that don't currently pass a model. I'm refraining from this as much as possible. I'm not sure how I would go about doing such, but it seems like that would over-complicate the situation.
How can I go about pushing this CurrentPermissions object (generated from a call to my TransactionManager) to every view (specifically, the Layouts!)
Your approach is what we use in out projects... and we use this approach to systematically remove the use of ViewBag changing it to ViewModels.
Other approach we have used (for UserPreferences in my case) is adding an ActionFilter that ends including the preference in the ViewBag. You decorate the actions needing it with [IncludePreferences] in my case (that is the name of my filter attribute.
EDIT ActionFilter:
public class IncludePreferencesAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller as BaseController;
// IController is not necessarily a Controller
if (controller != null)
{
//I have my preferences in the BaseController
//and cached but here you can query the DB
controller.ViewBag.MyPreferences = controller.TenantPreferences;
}
}
}
In you action you decorate it using [IncludePreferences]
As a temporary solution, I'm doing the following at the top of my Layout:
#{ OurModel.SupervisorRestriction CurrentSupervisorRestrictions = ViewBag.CurrentSupervisorRestrictions ?? Model.CurrentSupervisorRestrictions; }
This way, if we're passing in an object then it works just fine. Otherwise, I'll directly pass in a ViewBag.CurrentSupervisorRestrictions from the controller. There are only a few cases, so it's not that bad.
Better suggestions would be great, though.
I have raised similar question before, have got no answers.
How can I create a generic mvc4 view that can display list of or a single model that is passed to it. model can be either Person or Organization or Party whatever that is passed to it.
If you are looking for something like:
#model MyViewModel<T> where T : IViewModel
... then that is not supported by Razor.
You may be able to use something like this:
#model MyViewModel<IViewModel>
... that way you could define all types that could be passed as follows
public class Person : IViewModel { ... }
public class Organisation : IViewModel { ... }
public class Party : IViewModel { ... }
Please, DON'T DO THAT!!
You should make a view for each kind of object / list of objects.
However, yu can still reuse elements:
keep the common part (menu, header, footer...) on the site layout
make a view for each kind of object
make a view for each kind of list. in this vie you can use the object's view as a partial view and render it as many times as object are on the list.
Another possibility is to make templates for "Display For" for each kind of object. You can define a view for each kind of object, and store it in an special folder. When you use Html.Display or Html.DisplayForin your templates, the system will choose and render the right template depending on the type of the object to display. (You could also make named templates, and select them by name). For an introduction on this technique, look at this excellent posts by Brad Wilson.
But I insist, please, don't make a "generic view", as this will add extra complexity (check if it's a list or a simple object, get the type of the object, choose how to display it and display it). You can make very simple views by reusing the elements as explained, and letting the controllers decide which view to show for each object or list of object. Or use templates. In this way your system will be easier to maintain and less prone to errors because of added complexity (you don't need to change the same template all the time, but to add new templates, with very few code on them)
What I can't understand is why you want to have a simple view. What's the reason for it?
#model MyViewModel<IViewModel>
If you define a model like this then this error occurs:
Server Error in '/' Application.
The model item passed into the dictionary is of type MyViewModel\'1[Person], but this dictionary requires a model item of type MyViewModel'1[IViewModel].
To achieve a Generic View Use below code. dynamic is an inbuilt keyword that accepts any model.It worked fine for me
#model dynamic
or
#model IEnumerable<dynamic>
I'm using ASP.NET MVC2 and have various controllers in various areas.
In many of these I need to select a value from a list of values contained in a database; selecting a product or an employee for example.
I'm currently thinking of having a controller dedicated to getting these lists of things for use with dropdownlists etc. This controller would simply query the DAL and serve up JSON objects to be loaded with an ajax call on any view that needed them.
My only concern with this is that my view will be getting data from different controllers at once.
Am I right to be concerned? Is there a better way of setting this up, maybe creating a Product/Employee class especially to create a shared strongly typed partial view from?
Create another class which acts as a middle layer between your controllers and data access code. You can call this class methods from differnt controllers now.
public class ItemService()
{
public static List<Items> GetItems()
{
var items=yourRepositary.GetItems();
return items;
}
}
You can call it from your different controllers now
public ActionResult GetItems()
{
var items=ItemService.GetItems();
return Json(items,JsonRequestBehavior.AllowGet);
}
Best solution imho is to create a custom ActionFilterAttribute that populates the ViewData dictionary with whatever data you need to render on the views. You can then create extensions for ViewDataDictionary to access this info in a type-safe manner from the views, or throw an exception if the ViewData does not contain the data (ie prompting you to add the action filter attribute above your controller method). Using inheritance could get you in a mess further up the road.
Another approach would be to use a base class controller that implements this common functionality, then inherit other concrete controllers (paired with views) from this.
This approach would support a situation where there are lots of different lists, or the lists needed building dynamically in response to input paramters.
The ActionFilterAttribute approach might be better suited to situations where there are fewer, more static lists.