I am about to upgrade our software from ASP.NET WebForms to .NET MVC. All over the web it shows how to create a view based on a model, which is fine.
In this project the users can hide properties of the model to generate a view suitable for them, yet another client in another website and hide other properties.
The code is all the same, but i would like to know if there is a way to hide/show properties of a model based on a condition easily, hopefully without having a lot of IF statements all over my views.
Example - How can 1 client see only name and town, yet another client see all 3 properties. Just need to show based on a condition.
public class MyObject() {
public property name { get; set; };
public property town { get; set; };
public property customText { get; set; }
public MyObject() {}
}
NOTE: Users can also determine the order of these properties, can i do that as well easily ?
Just to say that creating separate views is not possible. The above is a very simple example of a model with properties. Our models can have about 100 properties, and the user can turn these on and off whenever they like, so it needs to be able to be done dynamically
Is there a way of creating a ViewModel on the fly?
Thanks in advance
Create a Property class or similar and model you data appropriately:
public class Property
{
public string Name {get;set;}
public bool Visible {get;set;}
public int Order {get;set;}
}
Then your view model can be similar to your example:
public class ViewModel
{
public Property Name {get;set;}
public Property Town {get;set;}
public Property CustomText {get;set;}
}
Well you cannot bind multiple models to your view.Obviously you have to do workaround in your view based on user roles.
Or else create a seperate model and view for each user roles.
I have been working on a project called Dynamic MVC.
http://dynamicmvc.com
It currently does not do what your asking. The functionality is already there, it is just not exposed the way you need it. However, if you are interested I will add the functionality so you can pass the properties you want to display in the querystring. Eventually, a customizable dynamic view will generate your page for you without any coding required. Also, the order of the properties would determine the order on your page. This would work for any model with the DynamicEntity attribute.
Let me know if your interested and I can include it in the next release.
Related
I am creating a dashboard, on this dashboard I have multiple instantiations of the same web user control.
Each web user control contains its own hidden fields. These hidden fields overwrite each other which causes it to always return the last set value for all the instantiated web user controls.
Is there anyway I can get around this?
[Edit:]
This is what is supposed to happen:
I advice you to use that kind of data modeling in order to use one hidden field for each usercontrol:
public class MainModel
{
public List<UserControl> {get;set;}
public string otherfield {get;set;}
}
public class UserControl
{
public string showableField {get;set;}
public int hiddenfield {get;set;}
}
See more for model binding in scott hanselman wensite
How would one go about validating a nested List of Objects in an MVC Model?
I have an "Item" object which has an attached List of Revenue Entries:
public class ItemModel
{
public int ItemID { get; set; }
public virtual List<RevenueEntryModel> Revenues { get; set;}
}
This list can be edited on the page dynamically, and each item is validated individually using it's own model - "RevenueEntryModel". However, I want to be able to restrict users from entering Items without any Revenues.
Is it possible to validate whether this Revenues list is empty using Data Annotations? I'm already using Foolproof but I'm pretty sure it doesn't include this functionality.
There's a previous answer that will help you here. It's a thorough answer, but basically you need to use custom validation attributes:
You can apply your own logic that checks the number of items in the Revenues collection.
Apply a class level validation attribute to the ItemModel class. You could use System.ComponentModel.DataAnnotations.CustomValidationAttribute for this.
This points to a custom method you would create.
The attribute construct would look something like this:
[CustomValidation(typeof (MyClassWhereMethodIsLocated), "MyStaticMethodName")]
Checkout this blog for additional details
I have a model which contains lists of other models, which also contains lists of other model types like the following for example:
public class Report
{
public string ReportId {get; set;}
public List<ReportOutput> ReportOutputs;
}
//output types = PDf, csv, txt, etc.
public class ReportOutput
{
public int OutputType {get; set;}
public List<DeliveryMethod> DeliveryMethods;
}
//delivery methods = email, ftp, etc.
public class DeliveryMethod
{
public string MethodName {get; set;}
}
I have a view that dynamically creates elements based on the contents of these objects using jQuery. The view allows users to check checkboxes to add or remove different outputs and within each output, different delivery methods. I need to know how to get the information back to the controller to load into a model to send back to the database. From reading around, it seems that I would just need to instantiate a model in the controller, then give each element in the view a name which corresponds to the model's properties and than call the controller function to retrieve all the data and continue the saving with the newly filled model, but my attempts at creating this controller function have failed.
So my question is, how would I create the controller function and do I just need to use the corresponding names on the html elements to allow a model to be created based on the information on the view?
If you follow the below pattern in generating name of form fields, the default model binder will take care of the rest else you have to do the model binding process yourself (tough job!).
ReportId,
ReportOutputs[0].OutputType,
ReportOutputs[0].DeliveryMethods[0].MethodName,
ReportOutputs[0].DeliveryMethods[1].MethodName,
ReportOutputs[1].OutputType,
ReportOutputs[1].DeliveryMethods[0].MethodName,
You should checkout the following article which covers those subjects and explains the naming conventions of your input fields that the default model binder expects so that it can bind them back when the form is submitted.
In my MonoDevelop project I have an iPhone app. I have two different views. Each view contains a UITable. For view 1 I have class 1 hooked to the UITable as Datasource 1. For View 2 I have a class 2 hooked up as Datasource 2. Both classes (i.e. Datasources) feed the tables with data. View 2 also has a custom cell and because of this loads asynchronous.
I get the data from 2 XML files using linq to XML. Everything works and the data loads great. What I need to do know is to load data in Datasource 2 based on the selection made in View 1. To do this I need to pass an ID from view 1 to Class(Datasource) 2. Problem.
I have tried just about everything I know but I just can't get it right.
The correct solution according to me:
I have created another class called SelectedRound with two properties. Code:
using System;
namespace xxxxx
{
public class SelectedRound
{
public string RoundID { get; set; }
public string Date { get; set; }
}
}
When I set RoundID in class 1 then I can access it in class 1. Trying to access it in class 2 however, returns nothing or null. Why would this happen? Could it be because Class(Datasource) 2 is loading asynchronously? Should I instantiate the SelectedRound class in some global way? If so how? AppDelegate maybe? (I am struggling to do that as well).
It seems pointless to me that setting and getting a simple string variable is difficult.
This feels like it is all about how you are passing the SelectedRound instance from the first view to the second.
As a very quick and dirty solution you could just use a singleton or could just use a static class:
public static class SelectedRound
{
public static string RoundID {get;set;}
public static string Date {get;set;}
}
For a more sophisticated pattern, then try overriding the constructors of one or both of your two view controllers in order to pass them a shared instance of your non-static class.
The view controllers may feel foreign to you right now - but they are just c# classes - so feel free to extend them by writing overrides, new methods and properties.
Many tutorials say that when i have to pass data from controller to view the best way is to create a flattern viewMoldel.
This solution came to solve also other problems (like the eager loading problem).
My concern is that when i create a flatten viewModel I lose all the informations that I store in the entities via annotation.
Suppose that i have a model composed by
class product{
[DisplayName("Name")]
public String Name{get;set;}
[DisplayName("Image")]
public String Image{get;set;}
[DisplayName("Description")]
public String Description{get;set;}
public String CategoryId{get;set;}
}
class category{
[DisplayName("Code")]
Public String Id{get;set;}
[DisplayName("Category name")]
public String Name{get;set;}
}
To render a grid that show product informations many tutorials say that the best way is to provide a flatten viewModel like this:
class productGridViewModel{
Public String ProductName{get;set}
Public String ProductImage{get;set}
Public String ProductDescription{get;set}
Public String CategoryName{get;set}
}
My concern is that I need to write again all the DisplayName annotations in the viewModel.
If you are flattening your model entities into ViewModels, shouldn't the attributes be removed from the model entity classes and placed on the ViewModels? Your model entities will not be used for display, so they should not have those attributes.
One simple solution is to have read-only properties in the viewModel which read the meta-data of the underlying Model object. Then you can bind this meta-data with the appropriate control in the View.
As below:
class productGridViewModel{
Public String ProductName{get;set}
Public String ProductImage{get;set}
Public String ProductDescription{get;set}
Public String CategoryName{get;set}
public string ProductDisplayName
{
get
{
//Please dont mind this code.. I am sure you can write it in much better way.
return typeof(Producy).GetProperty("Name").GetCustomAttributes(typeof(DisplayName))[0].ToString();
}
}
}
Your view model is your data consumption use case. If you need metadata then the view model flattened or otherwise will need to support it. May be you need to add it dynamically? Or if that's too onerous, then you need to encode it at compile time.
Edit.
You can use T4 transformations to ensure that dependent code it kept up to date. In fact we use this allow users to customise the DB and thus allow express the customisations in the view models.
What you do is put the source of the truth in one assembly, and then use a T4 transform file to create other representations from this assembly using reflection in another assembly.
The way to do it would be by implementing a custom AssociatedMetadataProvider. This isn't as much work as you'd think, and you could implement one to generate metadata from an xml file, database, convention, or even buddy types like the current one does.
The only thing you'd need to do differently to the current implementation is allow buddy types to contain field/properties which don't exist on the model they apply to, because that is the only thing currently preventing you from creating a buddy type which you could apply to all view/editor models of your particula model.
Its a bit of work and depends how much time it would save you but don't forget most of the MVC source code is available and you wouldn't have to change very much
Martin