Here's an example of how to go about this.
What we'll do is create a simple class called Person and display some basic information about them.
A Person has two properties
The IsActive
property is a bool value and will be the property used to determine what the user's name is displayed as.
Ultimately what we'll do is apply a new attribute called DisplayIf
to the Name property. It looks like this:
[DisplayIf("IsActive", "This value is true.", "This value is false.")]
First, let's create our model. Create a class called Person and put it into a Models folder.
Models/Person.cs
public class Person
{
[DisplayIf("IsActive", "This value is true.", "This value is false.")]
public string Name { get; set; }
public bool IsActive { get; set; }
}
Create a folder called Attributes and then put the following class in it:
Attributes/DisplayIfAttribute.cs
public class DisplayIfAttribute : Attribute
{
private string _propertyName;
private string _trueValue;
private string _falseValue;
public string PropertyName
{
get { return _propertyName; }
}
public string TrueValue
{
get { return _trueValue; }
}
public string FalseValue
{
get { return _falseValue; }
}
public DisplayIfAttribute(string propertyName, string trueValue, string falseValue)
{
_propertyName = propertyName;
_trueValue = trueValue;
_falseValue = falseValue;
}
}
Let's create a simple controller and action. We'll use the common /Home/Index.
Controllers/HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
HomeIndexViewModel viewModel = new HomeIndexViewModel();
Person male = new Person() { Name = "Bob Smith", IsActive = true };
Person female = new Person() { Name = "Generic Jane", IsActive = false };
Person[] persons = {male, female};
viewModel.Persons = persons;
return View(viewModel);
}
}
Create a new folder called ViewModels and create a HomeViewModels.cs class.
ViewModels/HomeViewModels.cs
public class HomeIndexViewModel
{
public IEnumerable<Person> Persons { get; set; }
}
Our Index view is very simple.
Views/Home/Index.cshtml
@model HomeIndexViewModel
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div>
@Html.DisplayForModel()
</div>
DisplayForModel
will work when you create this display template:
Views/Home/DisplayTemplates/HomeIndexViewModel.cshtml
@model HomeIndexViewModel
@Html.DisplayFor(m => m.Persons)
DisplayFor
-> Persons will work when you create this display template:
Views/Shared/DisplayTemplates/Person.cshtml
@model Person
@foreach (var prop in ViewData.ModelMetadata.Properties)
{
if (prop.HasDisplayIfAttribute())
{
<p>@Html.DisplayIfFor(x => prop)</p>
}
else
{
<p>@Html.DisplayFor(x => prop.Model)</p>
}
}
But what are these methods in this display template? Create a new folder called Extensions and add the following classes:
Extensions/ModelMetaDataExtensions.cs
public static class ModelMetaDataExtensions
{
public static bool HasDisplayIfAttribute(this ModelMetadata data)
{
var containerType = data.ContainerType;
var containerProperties = containerType.GetProperties();
var thisProperty = containerProperties.SingleOrDefault(x => x.Name == data.PropertyName);
var propertyAttributes = thisProperty.GetCustomAttributes(false);
var displayIfAttribute = propertyAttributes.FirstOrDefault(x => x is DisplayIfAttribute);
return displayIfAttribute != null;
}
}
Extensions/HtmlHelperExtensions.cs
public static class HtmlHelperExtensions
{
public static IHtmlString DisplayIfFor<TModel, TProperty>
(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
where TProperty : ModelMetadata
{
string returnValue = string.Empty;
var modelMetaData = expression.Compile().Invoke(helper.ViewData.Model);
var containerType = typeof(TModel);
var containerProperties = containerType.GetProperties();
var propertyInfo = containerProperties
.SingleOrDefault(x => x.Name == modelMetaData.PropertyName);
var attribute = propertyInfo.GetCustomAttributes(false)
.SingleOrDefault(x => x is DisplayIfAttribute) as DisplayIfAttribute;
var conditionalTarget = attribute.PropertyName;
var conditionalTargetValue = (bool)containerType
.GetProperty(conditionalTarget).GetValue(helper.ViewData.Model);
if (conditionalTargetValue)
{
returnValue = attribute.TrueValue;
}
else
{
returnValue = attribute.FalseValue;
}
return MvcHtmlString.Create(returnValue);
}
}
The final output:
