views:

167

answers:

2

Why can't I set ShowForEdit model metadata with an attribute?

It seems that the only attribute provided to alter this is [ScaffoldColumn], which sets both ShowForEdit and ShowForDisplay, which is not what I want to do. I want to be able to annotate the two separately from on my model.

+2  A: 

What is the type of property you are applying it to? If we use Reflector, we can discover that the ShowForEdit and ShowForDisplay properties are used in the following functions:

ShowForEdit: System.Web.Mvc.Html.DefaultEditorTemplates.ShouldShow(...)

ShowForDisplay: System.Web.Mvc.Html.DefaultDisplayTemplates.ShouldShow(...)

The definition of these methods is:

private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
{
  return (((metadata.ShowForEdit && (metadata.ModelType != typeof(EntityState))) && !metadata.IsComplexType) && !templateInfo.Visited(metadata));
}

private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
{
  return (((metadata.ShowForDisplay && (metadata.ModelType != typeof(EntityState))) && !metadata.IsComplexType) && !templateInfo.Visited(metadata));
}

Ignoring the obvious property check (metadata.ShowForX), you can see that it is checking whether the model is an instance of EntityState (probably isn't), and then a check for metadata.IsComplexType.

We can look at the IsComplexType property here:

public virtual bool IsComplexType
{
  get
  {
    return !TypeDescriptor.GetConverter(this.ModelType).CanConvertFrom(typeof(string));
  }
}

What that is saying is that it will return true if the model cannot be converted from a string, and in the ShouldShow() methods, it will show if it is not a complex type, i.e., the value CAN be converted from a string.

What you will need to do, is create a TypeConverter that can convert a string, to the model, e.g:

A model:

[TypeConverter(typeof(ItemConverter))]
public class Item 
{
  #region Properties
  public string Text { get; set; }
  #endregion
}

And a converter:

public class ItemConverter : TypeConverter
{
  #region Methods
  public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  {
    if (sourceType == typeof(string))
      return true;

    return base.CanConvertFrom(context, sourceType);
  }

  public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  {
    if (value.GetType() == typeof(string)) 
    {
      return new Item { Text = (string)value };
    }

    return base.ConvertFrom(context, culture, value);
  }
  #endregion
}

With that in place, try it again and see if that helps.

Matthew Abbott
Wow. I don't know whether this is madness or brilliance. ;)
jfar
Lol, probably a bit of both ;)
Matthew Abbott
+2  A: 

Because it is not supported out of the box. AFAIK the reason is because the dataannotations attribute that support this functionality are in .net 4.0 and in order to make MVC 3.5 and 4.0 compatible they had to be excluded.

The easiest way to fix this is to have to implement your own Edit/Show attribute as demonstrated in this Question/Answer:

http://stackoverflow.com/questions/2959041/showing-different-fields-in-editorformodel-vs-displayformodel-modes-in-mvc2

jfar
Would that work for properties that aren't using primatives?
Matthew Abbott
Yes this works for non primitives.
jfar
Thanks for your answer.
UpTheCreek