2012-01-11 11 views
7

Ho un modello di vista condiviso da due pagine diverse. I modelli di visualizzazione sono abbastanza simili con l'eccezione di una proprietà: Indirizzo. Il modello di vista contiene i campi nome e posizione. Tuttavia, l'etichetta dell'indirizzo della vista cliente dovrebbe contenere: Indirizzo cliente e l'etichetta dell'indirizzo della vista dipendente deve contenere: Indirizzo dipendente. Visualizzeranno anche diversi messaggi di errore.Sovrascrittura delle proprietà di un modello di vista di base in ASP.NET MVC 3

Ecco una versione semplificata di quello che sto cercando di realizzare:

public class BaseLocation 
{ 
    [Display(Name="Your Name")] 
    public string Name {get;set;} 

    public virtual string Address {get;set;} 
} 

public class CustomerLocation : BaseLocation 
{ 
    [Display(Name="Customer Address")] 
    public override string Address {get;set;} 
} 

public class EmployeeLocation : BaseLocation 
{ 
    [Display(Name="Employee Address")] 
    public override string Address {get;set;} 
} 

Poi ho creato un parziale per la posizione di base, in questo modo:

@model BaseLocation 
***ASP.NET MVC Helpers here: labels, text, validation, etc. 

Infine, il Cliente e Pagine dei dipendenti, chiamerei il partial e invialo il tipo sottoclasse.

Customer.cshtml 
@model CustomerLocation 
@Html.Render("_BaseLocation", Model) 


Employee.cshtml 
@model EmployeeLocation 
@Html.Render("_BaseLocation", Model) 

Il risultato è che non vedrei gli attributi dei dati per il tipo specifico. Ad esempio, nella pagina cliente, otterrei l'etichetta "Indirizzo" anziché "Indirizzo cliente".

Preferisco non creare due partial con gli stessi dati per ogni tipo specifico, semplicemente perché una proprietà nel modello di visualizzazione condivisa deve avere un'etichetta e un messaggio di errore diversi. Qual è il modo migliore per farlo? Grazie.

+0

Prova a fare la base astratta, vedere se cambia qualcosa. – gdoron

+0

@gdoron, non cambierà nulla. –

+0

@DarinDimitrov, quindi l'unico modo in cui riesco a pensare è scrivere il proprio 'HtmlHelper' che fa bene il lavoro. – gdoron

risposta

1

A causa del modo in cui l'ereditarietà della vista funziona e di come è definito il modello, il parametro passato a qualcosa come LabelFor e TextBoxFor utilizza il tipo di modello definito nella classe. Nel tuo caso sarà sempre BaseLocation ed è per questo che non viene sovrascritto.

Non è necessario creare partial per la classe, ma è necessario creare due visualizzazioni una per cliente e una per dipendente. Poiché hai già due viste specifiche per ogni tipo, dovrai solo creare un'altra vista di posizione o unire la vista di baselocation in quella di genitore.

Customer.cshtml 
@model CustomerLocation 
@Html.Render("_CustomerBaseLocation", Model) 


Employee.cshtml 
@model EmployeeLocation 
@Html.Render("_EmployeeBaseLocation", Model) 

Sono assolutamente a capire il problema dal momento che si desidera solo cambiare un punto di vista e si potrebbe avere molti di questi tipi simili di situazioni già con BaseLocation.

È potrebbe fare qualcosa di simile ...

public static IHtmlString LabelTextFor<TModel, TValue>(this HtmlHelper<TModel> html, object model, Expression<Func<TModel, TValue>> expression) 
{ 
    MemberExpression memberExpression = (MemberExpression)expression.Body; 
    var propertyName = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null; 

    //no property name 
    if (string.IsNullOrWhiteSpace(propertyName)) return MvcHtmlString.Empty; 

    //get display text 
    string resolvedLabelText = null; 
    var displayattrib = model.GetType().GetProperty(propertyName) 
       .GetCustomAttributes(true) 
       .SingleOrDefault(f => f is DisplayAttribute) 
             as DisplayAttribute; 
    if (displayattrib != null) { 
     resolvedLabelText = displayattrib.Name; 
    } 

    if (String.IsNullOrEmpty(resolvedLabelText)) { 
     return MvcHtmlString.Empty; 
    } 

    TagBuilder tag = new TagBuilder("label"); 
    tag.Attributes.Add("for", TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(""))); 
    tag.SetInnerText(resolvedLabelText); 
    return new HtmlString(tag.ToString()); 
} 

Poi, nel tuo _BaseLocation.cshtml si farebbe una chiamata del tipo:

@Html.LabelTextFor(Model, m => m.Address) 

Scrivi metodo di estensione personalizzata per fare questo è tutto quello che posso pensare di

+0

Questo particolare metodo si basa su 'DisplayAttribute' e non consente metodi alternativi di aggiungere modelMetadata come usare 'IModelMetadata'. – Buildstarted

Problemi correlati