开发者

How to inject custom ModelMetadata properties and use them in Html helpers

开发者 https://www.devze.com 2023-02-10 04:22 出处:网络
The idea (simplified) is to have user definable properties in ViewModel contained in a dictionary. Something along these lines:

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号