MVC2 - كيفية الحصول على نموذج الوالدين (الحاوية) داخل القالب

StackOverflow https://stackoverflow.com/questions/4009129

سؤال

أنا أكتب تطبيق MVC2 باستخدام DataAntations. لدي نموذج التالي:

public class FooModel 
{
    [ScaffoldColumn("false")]
    public long FooId { get; set; }

    [UIHint("BarTemplate")]
    public DateTime? Bar { get; set;}
}

أريد إنشاء قالب عرض مخصص للشريط. لقد أنشأت القالب التالي:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>

<div class="display-label">
    <span><%: Html.LabelForModel() %></span>
</div>
<div class="display-field">
    <span><%: Html.DisplayForModel()%></span>
    <%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %>
</div>

الآن ، مشكلتي هي ذلك القالب الداخلي للشريط ، أريد الوصول إلى خاصية أخرى من النموذج الخاص بي. لا أرغب في إنشاء قالب منفصل لـ Foomodel لأنه أكثر مما سأضطر إلى ترميز جميع خصائص Foomodel الأخرى.

بعد تحقيق موجز مع مصحح أخطاء أستطيع أن أرى ذلك:

  1. this.ViewData.ModelMetadata.ContainerTypeهو FooModel (كما هو متوقع)
  2. this.ViewData.TemplateInfo لديه ممتلكات غير عامة VisitedObjects(من النوعSystem.Collections.Generic.HashSet<object>) الذي يحتوي على عنصرين:FooModel و DateTime?.

كيف يمكنني الوصول إلى Foomodel الخاص بي؟ لا أريد أن أخترق طريقي باستخدام التفكير.

تحديث:

لقد قبلت إجابة Mootinator لأنها تبدو لي أفضل حل يسمح بسلامة النوع. لقد قمت أيضًا بإصابة إجابة TX3 ، حيث أن إجابة Mootinator تبني عليها. ومع ذلك ، أعتقد أنه يجب أن يكون هناك نموذج دعم أفضل MVC في هذا النوع من السيناريوهات ، والتي أعتقد أنها شائعة جدًا في العالم الحقيقي ولكنها مفقودة من تطبيقات العينات.

هل كانت مفيدة؟

المحلول

آسف إذا كان هذا الاقتراح يبدو غامضًا ، لم أجربه ، لكن ألا يمكنك أن تفعل ما اقترحه TX3 دون الحاجة إلى إنشاء مجموعة من الفصول الجديدة عن طريق تحديد فئة عامة للرجوع إلى أي نوع من الوالدين الذي تريده؟

    public class FooModel 
    {
        [ScaffoldColumn("false")]
        public long FooId { get; set; }

        [UIHint("BarTemplate")]
        public ParentedDateTime<FooModel> Bar { get; set;}

        public FooModel()
        {
            Bar = new ParentedDateTime<FooModel>(this);
        }
    }


    public class ParentedDateTime<T>
    {
        public T Parent {get; set;}
        public DateTime? Babar {get; set; }

        public ParentedDateTime(T parent)
        {
            Parent = parent;
        }

}

يمكنك توسيع ذلك لتغليف أي نوع قديم مع أ <Parent, Child> كتاب عام ، حتى.

هذا من شأنه أن يمنحك أيضًا الفائدة التي سيكون قالبها المكتوب بقوة

Inherits="System.Web.Mvc.ViewUserControl<ParentedDateTime<FooType>> وبالتالي ، لن تضطر إلى تفسير اسم القالب الذي يجب استخدامه في أي مكان. هذا هو أكثر كيف تهدف الأمور إلى العمل.

نصائح أخرى

ربما يمكنك إنشاء فئة جديدة ، دعنا نقول userDateTime وسيحتوي على وقت لا لبس فيه وبقية المعلومات التي تحتاجها. بعد ذلك ، يمكنك استخدام قالب العرض المخصص لـ UserDateTime والوصول إلى المعلومات التي تحتاجها.

أدرك أنك قد تبحث عن نوع آخر من الحلول.

أعتقد أنك قد تكون أفضل حالًا في استخراج هذه الوظيفة لمكالمة HTMLHelper من عرض الوالدين.

شيء مثل RenderSpecialDateTime<TModel>(this HtmlHelper html, Expression<Func<TModel,DateTime?>> getPropertyExpression) ربما تفعل المهمة.

خلاف ذلك ، سيكون عليك أن تفعل شيئًا مثل ما اقترحه TX3. لقد رفعت إجابته ، لكنني نشرت هذا كبديل.

ألا يمكنك استخدام كائن قاموس ViewData في وحدة التحكم ثم الاستيلاء على ذلك في ViewUserControl؟ لن يتم كتابتها بقوة ولكن ... يمكنك كتابة مساعد لعدم القيام بأي شيء إذا كان فارغًا ، وربط ليقول صفحة سجل تسجيل الدخول على سبيل المثال إذا كان لها قيمة.

يبدو أنه في مكان ما بين MVC 5.0 و 5.2.2 تم إضافة خاصية "حاوية" إلى فئة ModelMetadata.

ومع ذلك ، نظرًا لأن جميع الأساليب في مزود مسؤول عن إنشاء البيانات الوصفية (getMetAdataForProperty ، إنشاء إلخ) ، لا تحتوي على حاوية في توقيعها ، يتم تعيين خاصية الحاوية فقط في حالات معينة (GetMetAdataforProperties و getMetAdataFrovider وفقًا للقانون المنعكس) كان عادة لاغية.

لذا فإن ما انتهى بي الأمر هو التغلب على getMetadataforProperty في مزود بيانات تعريف جديدة ووضعه هناك:

public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
{
  var propMetaData = base.GetMetadataForProperty(modelAccessor, containerType, propertyName);
  Object container = modelAccessor.Target.GetType().GetField("container").GetValue(modelAccessor.Target);
  propMetaData.Container = container;
  return propMetaData;
}

أعلم أن هذا انعكاس لكنه مقتلم إلى حد ما. يبدو أن MS تقوم بتصحيح هذا الزائد ، لذا ربما يكون من الممكن استبدال رمز الانعكاس في المستقبل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top