Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create conditional attribute as DisplayIf?

I want to create an attribute to use with my viewmodel. I want to display different textstrings depending on a third value.

I would like to do something like this...

[DisplayIf("IsPropertyValid", true, Name="value 1")]
[DisplayIf("IsPropertyValid", false, Name="value 2")]
public string MyProperty { get; set; }

public bool IsPropertyValid { get; set; }

Depending on whether my value IsPropertyValid is true or not I want to show one or the other. Ie. When property IspPropertyValid equals true "value 1" will be the displaytext and if not it will be "value 2".

Is this possible with ASPNET.MVC attributes? Or even better... a combinated one like....

[DisplayIf("IsPropertyValid", new {"value 1", "value 2"})].
public string MyProperty { get; set; }

public bool IsPropertyValid { get; set; }

Then the attribute checks the value of IsPropertyValid and makes sure the value displayed is "value 1" or "value 2".

like image 974
Per Avatar asked Nov 27 '13 23:11

Per


People also ask

How do I create a conditional attribute in MicroStrategy?

In MicroStrategy Web, open the document in Design or Editable Mode. Point to Conditional Formatting, then select Advanced. The Visual Conditional Formatting Editor opens. From the drop-down list at the top left, select the metric that you want to apply the formatting to.

What is a conditional attribute?

A conditional attribute is a tag used to mark a method or class whose execution depends on the definition of preprocessing identifier. A conditional attribute indicates a condition to specify conditional compilation wherein methods are selectively called on the basis of definition of symbols.


1 Answers

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

  • Name
  • IsActive

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:

Output

like image 112
Rowan Freeman Avatar answered Oct 20 '22 03:10

Rowan Freeman