Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Wednesday, March 30, 2016

@Html.EnumDropDownListFor in MVC

For MVC v5.1 use Html.EnumDropDownListFor

        @Html.DropDownList("MyType", 
           Html.GetEnumSelectList(typeof(MyType)) , 
           "Select My Type", 
           new { @class = "form-control" })
    

For MVC v5 use EnumHelper

        @Html.DropDownList("MyType", 
           EnumHelper.GetSelectList(typeof(MyType)) , 
           "Select My Type", 
           new { @class = "form-control" })
    

For MVC >5 and lower

I rolled Rune's answer into an extension method:
        namespace MyApp.Common
        {
            public static class MyExtensions{
                public static SelectList ToSelectList(this TEnum enumObj)
                    where TEnum : struct, IComparable, IFormattable, IConvertible
                {
                    var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                        select new { Id = e, Name = e.ToString() };
                    return new SelectList(values, "Id", "Name", enumObj);
                }
            }
        }
    
This allows you to write:
     ViewData["taskStatus"] = task.Status.ToSelectList();
    
by
using MyApp.Common

Alternatively:
Create a custom helper class and use Html.EnumDropDownListFor for all lower version MVC < 5.1 (i.e. 3.x, 4.x, 5.0). Here is the class code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Mvc.Html;
/// 
/// Class ENUM Helper
/// 
public static class EnumHelper
{
    /// 
    /// The single empty item
    /// 
    private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = string.Empty, Value = string.Empty } };
    /// 
    /// Gets the ENUM description.
    /// 
    /// The type of the ENUM.
    /// The value.
    /// ENUM Description
    public static string GetEnumDescription(TEnum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        if ((attributes != null) && (attributes.Length > 0))
        {
            return attributes[0].Description;
        }
        else
        {
            return value.ToString();
        }
    }
    /// 
    /// ENUMS the drop down list for.
    /// 
    /// The type of the model.
    /// The type of the ENUM.
    /// The HTML helper.
    /// The expression.
    /// MVC Html String
    public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper, Expression> expression)
    {
        return EnumDropDownListFor(htmlHelper, expression, null);
    }
    /// 
    /// ENUMS the drop down list for.
    /// 
    /// The type of the model.
    /// The type of the ENUM.
    /// The HTML helper.
    /// The expression.
    /// The HTML attributes.
    /// MVC Html String
    public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper, Expression> expression, object htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        Type enumType = GetNonNullableModelType(metadata);
        IEnumerable values = Enum.GetValues(enumType).Cast();
        IEnumerable items = from value in values
                                            select new SelectListItem
                                            {
                                                Text = GetEnumDescription(value),
                                                Value = value.ToString(),
                                                Selected = value.Equals(metadata.Model)
                                            };
        // If the enum is nullable, add an 'empty' item to the collection
        if (metadata.IsNullableValueType)
        {
            items = SingleEmptyItem.Concat(items);
        }
        return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
    }
    /// 
    /// Gets the type of the non null-able model.
    /// 
    /// The model metadata.
    /// real Model Type
    private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
    {
        Type realModelType = modelMetadata.ModelType;
        Type underlyingType = Nullable.GetUnderlyingType(realModelType);
        if (underlyingType != null)
        {
            realModelType = underlyingType;
        }
        return realModelType;
    }
}

Usage:

   @Html.EnumDropDownListFor(model => model.EnumProperty, "Select Enum", new { @class = "form-control", type = "text"})

Thursday, October 8, 2015

Some useful c# code snippets for visual studio users

Public Class - code snippet

(Code snippet for public class)
Many times we, visual studio users, use common code snippets (already available with visual studio setup) like for, if, class, prop etc...
Out of these class is used many times, an every time we need to prepend Public with generated class declaration. So to automate this here I have created a custom C# code snippet that generates code for class declaration along with Public :

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
 <CodeSnippet Format="1.0.0">
  <Header>
   <Title>pclass</Title>
   <Shortcut>pclass</Shortcut>
   <Description>Code snippet for public class</Description>
   <Author>Microsoft Corporation</Author>
   <SnippetTypes>
    <SnippetType>Expansion</SnippetType>
    <SnippetType>SurroundsWith</SnippetType>
   </SnippetTypes>
  </Header>
  <Snippet>
   <Declarations>
    <Literal>
     <ID>name</ID>
     <ToolTip>Class name</ToolTip>
     <Default>MyClass</Default>
    </Literal>
   </Declarations>
   <Code Language="csharp"><![CDATA[public class $name$
 {
  $selected$$end$
 }]]>
   </Code>
  </Snippet>
 </CodeSnippet>
</CodeSnippets>

Copy above code and save into a file with name - "pclass.snippet" at "%USERPROFILE%\Documents\My Projects\Code Snippets\Visual C#\My C# Code Snippets". After restarting visual studio in any C# class file, type pclass + tab and see the difference.

Property with matching name - code snippet

(Code snippet for property and backing field with matching name)
One more code snippet - propfull we use many times, an every time we need to change Property name and private variable name with generated class declaration, though we use the same name for both with prepending underscore(_). So to automate this here I have created a custom C# code snippet:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
 <CodeSnippet Format="1.0.0">
  <Header>
   <Title>propmatchname</Title>
   <Shortcut>propmatchname</Shortcut>
   <Description>Code snippet for property and backing field with matching name</Description>
   <Author>Microsoft Corporation</Author>
   <SnippetTypes>
    <SnippetType>Expansion</SnippetType>
   </SnippetTypes>
  </Header>
  <Snippet>
   <Declarations>
    <Literal>
     <ID>type</ID>
     <ToolTip>Property type</ToolTip>
     <Default>int</Default>
    </Literal>
    <Literal>
     <ID>property</ID>
     <ToolTip>Property name</ToolTip>
     <Default>MyProperty</Default>
    </Literal>
   </Declarations>
   <Code Language="csharp"><![CDATA[private $type$ m_$property$;
 public $type$ $property$
 {
  get { return m_$property$;}
  set { m_$property$ = value;}
 }
 $end$]]>
   </Code>
  </Snippet>
 </CodeSnippet>
</CodeSnippets>

Copy above code and save into a file with name - "propmatchname.snippet" at "%USERPROFILE%\Documents\My Projects\Code Snippets\Visual C#\My C# Code Snippets". After restarting visual studio in any C# class file, type propmatchname + tab and see the difference. Now try to change either public property name OR private variable name. Both will be in sync.


Hope many visual studio users/developers love this.
Enjoy !!!

Wednesday, October 7, 2015

Auto-ignore non existing destination properties with AutoMapper

By default, AutoMapper tries to map all properties of the source type to the destination type. If some of the properties are not available in the destination type it will not throw an exception when doing the mapping. However it will throw an exception when you are using ValidateMapperConfiguration().
Imagine if we have the following two types:
1
2
3
4
5
6
7
8
9
10
class SourceType
{
    public string FirstName { get; set; }
}
 
class DestinationType
{   
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
ValidateMapperConfiguration() will throw the following exception when you Map SourceType to DestinationType:
AutoMapper.AutoMapperConfigurationException : The following 1 properties on DestinationType are not mapped: 
 LastName 
Add a custom mapping expression, ignore, or rename the property on SourceType.
You can override this behavior by making a small extension method to ignore all properties that do not exist on the target type.
1
2
3
4
5
6
7
8
9
10
11
12
public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var sourceType = typeof(TSource);
    var destinationType = typeof(TDestination);
    var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType)
        && x.DestinationType.Equals(destinationType));
    foreach (var property in existingMaps.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}
Then it is possible to do the mapping as follows:
1
2
Mapper.CreateMap<SourceType, DestinationType>()
    .IgnoreAllNonExisting();
It is also possible to customize this method to your needs, by specifically ignoring properties which have a protected or private setter, for example.

Find a cool free stuff everyday

Giveaway of the Day

Hiren Bharadwa's Posts

DotNetJalps