The idea (simplified) is to have user definable properties in ViewModel contained in a dictionary. Something along these lines:
public class MyViewModel
{
[Required]
public string Name { get; set; }
[DisplayName("User address")]
public string Address { get; set; }
// ...
public IDictionary<string, string> MetaData { get; set; }
}
Let's say that MetaData contains several additional properties: PhoneNumber
, Email
, etc. that you can access with myViewModel.MetaData["PhoneNumber"]
.
What I would like to do is to be able to use those additional MetaData properties in Html helpers on View side, just like I would use normal properties.
So, in addition to using standard properties as:
Html.TextBox("Name")
I would also like to use those additional properties:
Html.TextBox("PhoneNumber")
My research lead me to inheriting from DataAnnotationsModelMetadataProvider
(since it's necessary to also support standard DataAnnotations attributes for standard properties) and trying to figure out 开发者_如何学Gowhat exactly to override there in order to inject additional properties as additional ModelMetadata elements, but I'm kind of stuck.
Am I on the right path? Any additional pointer that could help me here?
Thanks
An alternative option might be to construct a dynamic object similar to ViewBag/ViewData in MVC 3. You would have an object which you could access via Model.MetaData.Foo
and Foo
would actually map to a key in your dictionary.
The type which backs the ViewBag object is System.Web.Mvc.DynamicViewDataDictionary; this class is internal and sealed so you would have to make a custom implementation of it (unless there's a better option I'm unaware of). A quick glance at the MVC 3 sources furnished this:
internal sealed class DynamicViewDataDictionary : DynamicObject {
private readonly Func<ViewDataDictionary> _viewDataThunk;
public DynamicViewDataDictionary(Func<ViewDataDictionary> viewDataThunk) {
_viewDataThunk = viewDataThunk;
}
private ViewDataDictionary ViewData {
get {
ViewDataDictionary viewData = _viewDataThunk();
Debug.Assert(viewData != null);
return viewData;
}
}
// Implementing this function improves the debugging experience as it provides the debugger with the list of all
// the properties currently defined on the object
public override IEnumerable<string> GetDynamicMemberNames() {
return ViewData.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
ViewData[binder.Name] = value;
// you can always set a key in the dictionary so return true
return true;
}
}
One possible advantage to this solution over modifying the ModelMetadataProvider is that you wouldn't have to spend time building all the custom components for your scenario- the default providers should be sufficient.
精彩评论