ایجاد UI داینامیک برای مدل های Complex در MVC

شنبه 21 فروردین 1395

در این مقاله می خواهیم از مدل های پیچیده یا Complex در MVC استفاده کنیم و از طریق آنها صفحه نمایشی(UI) را به صورت داینامیک درآوریم. برای انجام این کار با مشکلاتی روبرو می شویم که در این مقاله به حل آنها می پردازیم.

 ایجاد UI داینامیک برای مدل های Complex در MVC

 MVC تعدادی متدهای کمک کننده(helper) ارائه کرده است که توسط آنها می توان بخش هایی از UI را به صورت اتوماتیک از روی مدل metadata ایجاد کرد، که به صورت زیر هستند:

@Html.Editor("Prop")
@Html.EditorFor(mdl => mdl.Prop)
@Html.EditorForModel()
@Html.Display("Prop")
@Html.DisplayFor(mdl => mdl.Prop)
@Html.DisplayForModel()

این متدها از یک مکانیزم بزرگ metadata discovery یا کشف metadata برای ایجاد UI مناسب استفاده می کنند، که شامل اعتبار سنجی های سمت کلاینت و سرور می باشد. این UI می تواند بیشتر بهبود پیدا کرده و با یک سیستم قالب گسترده(extensive templating) به صورت سفارشی درآید.

Property های مربوط به مدل Complex

توابع استفاده شده در UI از Property هایی غیر از Property های اولیه روی مدل شما صرف نظر می کنند. شما ممکن است یک Address property روی مدل Person خود داشته باشید که دو رشته property های City و Street را دارد. و ممکن است انتظار یک UI را داشته باشید که شامل دو text boxe برای هر دو آنها باشد، اما اینطور نیست!

البته شما می توانید کد را به صورت زیر استفاده کنید:

@Html.EditorForModel()
@Html.EditorFor(m=>m.Child)

اگر شما یک مدل complex به صورت hierarchy داشته باشید، ممکن است وقتی UI آن را به صورت زیر ایجاد می کنید، برای شما رضایت بخش نباشد:

@Html.EditorForModel()
@Html.EditorFor(m => m.Child)
@Html.EditorFor(m => m.Child.GrandChild)
@Html.EditorFor(m => m.Child.GrandChild2)
@Html.EditorFor(m => m.Child2)
@Html.EditorFor(m => m.Child2.GrandChild)
@Html.EditorFor(m => m.Child2.GrandChild2)
@Html.EditorFor(m => m.Child3)
@Html.EditorFor(m => m.Child3.GrandChild)
@Html.EditorFor(m => m.Child3.GrandChild2)

 

یا اگر مدلی داشته باشید که در زمان طراحی کاملا شناخته شده نباشد نیز ممکن است مشکل ایجاد کند. این زمانی اتفاق می افتد که شما View های چند ریختی دارید که شکل های مختلفی از کلاس پایه را عرضه می کنند و یا زمانی که شما مدل دارید که به صورت داینامیک ایجاد شده و پشت مکانیسم metadata discovery مخفی شده است.

راه حل این مشکل به چه صورت است؟

متد ( )CollectDescendantProperties مدل hierarchy را ایجاد کرده و لیست کاملی از Property ها را با metadata آنها و مسیر property های کامل فراهم ld کند( برای مثال Child3.GrandChild2) و آماده استفاده با (Html.Editor(desecendant.Path@ می باشد، به صورت زیر:

@functions
{
    IList<DescendantPropertyMetadata> CollectDescendantProperties(ModelMetadata modelMetadata)
    {
        var list = new List<DescendantPropertyMetadata>();
        CollectDescendantPropertiesRecursive("", list, modelMetadata, 0);
        return list;
    }

    void CollectDescendantPropertiesRecursive(string currentPath, 
    IList<DescendantPropertyMetadata> list, ModelMetadata modelMetadata, int incomingDepth)
    {
        int currentDepth = incomingDepth + 1;
        var complexProperties = ((IEnumerable<ModelMetadata>)modelMetadata.Properties.Where
                                (pr => pr.IsComplexType));
        foreach (var complexProperty in complexProperties)
        {
            string path = currentPath + (currentDepth == 1 ? "" : ".") + complexProperty.PropertyName;
            list.Add(new DescendantPropertyMetadata(path, currentDepth, complexProperty));
            CollectDescendantPropertiesRecursive(path, list, complexProperty, currentDepth);
        }
    }

    class DescendantPropertyMetadata
    {
        public DescendantPropertyMetadata(string path, int depth, ModelMetadata metadata)
        {
            Path = path;
            Depth = depth;
            Metadata = metadata;
        }
        public string Path { get; private set; }
        public int Depth { get; private set; }
        public ModelMetadata Metadata { get; private set; }
    }
}

 

شما می توانید این را در View به صورت زیر استفاده کنید:

@Html.EditorForModel();
var desecendants = CollectDescendantProperties(ViewData.ModelMetadata);
foreach (DescendantPropertyMetadata desecendant in desecendants)
{
    <h2>@desecendant.Metadata.PropertyName</h2>
    @Html.Editor(desecendant.Path)
}

توجه داشته باشید که شما می توانید کد این متد را refractor کرده و برای هرجایی خارج از این View نیز از آن استفاده کنید.

برای درک بهتر مطالب بالا یک نمونه برنامه به این مقاله ضمیمه شده است.

 

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید