4

私は、AdditionalValues などの代替アプローチを見ていますが、テンプレート ビューで使用可能な ModelMetadata オブジェクトに新しいプロパティを追加できるシナリオになる可能性があるかどうか疑問に思っています。

たとえば、次のようにすることができます。

@ViewData.ModelMetadata.MvvmBound

これを Editor および Display テンプレートで使用して、レンダリングされる HTML 要素に MVVM 属性を追加したいと考えています。

私は完全に迷っていますが、これまでの私の努力は次のとおりです。

public class MyModelMetaDataProvider : DataAnnotationsModelMetadataProvider
{
    protected new MyModelMetaData CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        ModelMetadata modelMetaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        MyModelMetaData myMetaData = (MyModelMetaData)modelMetaData;

        return myMetaData;
    }
}

public class MyModelMetaData: ModelMetadata
{
    public MyModelMetaData(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        : base(provider, containerType, modelAccessor, modelType, propertyName)
    {

    }

    public int MyProperty { get; set; }
}  

次に、グローバル asax で次を使用します。

ModelMetadataProviders.Current =new MyModelMetaDataProvider();

問題は、認識されないビューで MyProperty を使用しようとした場合です。これは、VS がカスタム ModelMetadata クラスを認識していないためです。

これが可能かどうかさえわかりませんか?

4

1 に答える 1

11

教室に辞書がありAdditionalValuesますModelMetadataここを参照

AdditionalMetadata次のように、属性を使用してそのディクショナリに値を追加できます。

public class DummyModel
{
    [AdditionalMetadata("MvvmBound", true)]
    public string PropertyA{ get; set; }

    public string PropertyB{ get; set; }
}

そして、エディター テンプレートでそれらを確認できますstring。たとえば、次のようになります。

@{
    bool isBound = false;
    if(ViewData.ModelMetadata.AdditionalValues.ContainsKey("MvvmBound"))
    {
        isBound = (bool)ViewData.ModelMetadata.AdditionalValues["MvvmBound"];    
    }
}

//use isBound to set some attributes in the html element

のエディタ テンプレートでこれらの属性を確認することもDummyModelできます。これは、次のように個々のプロパティのメタデータを取得することで実行できます。

@ModelMetadata.FromLambdaExpression(x => x.PropertyA, ViewData).AdditionalValues["MvvmBound"] 

このコードにはいくつかの欠点があります。このアプローチでは、キー名を AdditionalValues ディクショナリに渡す必要があり、オブジェクトから適切な型に値をキャストする必要もあります。キー名を手動で指定してキャストを手動で実行することなく、メタデータからその値を取得するための独自の拡張メソッドを作成できます。

public static class ModelMetadataExtensions
{
    public static bool IsMvvmBound(this ModelMetadata metadata)
    {
        if (!metadata.AdditionalValues.ContainsKey("MvvmBound")) return false;
        return (bool)metadata.AdditionalValues["MvvmBound"];
    }
}

これにより、エディター テンプレートのコードがよりクリーンになります。たとえば、DummyModel上記のエディター テンプレートでは、次のようなことができます (拡張メソッドの名前空間を /Views フォルダー内の Web.config ファイルに追加することを忘れないでください)。

<h3>WholeModel Is MvvmBound?: @ViewData.ModelMetadata.IsMvvmBound()</h3>
<h3>PropertyA Is MvvmBound?: @ModelMetadata.FromLambdaExpression(x => x.PropertyA, ViewData).IsMvvmBound()</h3>
<h3>PropertyB Is MvvmBound?: @ModelMetadata.FromLambdaExpression(x => x.PropertyB, ViewData).IsMvvmBound()</h3>

その拡張メソッドをカスタム属性の拡張IMetadataAwareと組み合わせることができるため、プロパティで使用するたびにメタデータ値のキーの名前をハードコードする必要はありません。

public class IsMvvmBoundAttribute : Attribute, IMetadataAware 
{
    public IsMvvmBoundAttribute()
    {
        this.IsMvvmBound = true;
    }

    public bool IsMvvmBound { get; set; }

    //This is the single method of IMetadataAware, and what allows us to add the values into the AdditionalValues dictionary
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues.Add("MvvmBound", this.IsMvvmBound);
    }
}

public class DummyModel
{
    //[AdditionalMetadata("MvvmBound", true)] <- replaced with the new attribute
    [IsMvvmBoundAttribute]
    public string PropertyA{ get; set; }

    public string PropertyB{ get; set; }
}

ModelMetadata.AdditionalValuesは であるためDictionary<string,object>、キーごとに単純な値を格納することに制限されません。上記のコードに従って、必要なすべてのプロパティを保持する独自のクラス、それらの各値を設定するために使用できる属性、およびそのクラスのインスタンスを AdditionalValues ディクショナリに保存する属性、およびインスタンスを抽出する拡張メソッドを作成できます。辞書からそのクラスの。

ご覧のとおり、独自のModelMetadataクラスを作成したり、ModelMetadataProvider.

それが役に立てば幸い!

于 2014-04-03T11:53:48.630 に答える