إنشاء واستخدام Partial View

-

Partial Views  هي ملفات View  منفصلة يمكن ادراج محتوياتها في Views أخرى. مثال - إذا كان لديك view يحتوي على محتويات تتكرر مرارًا وتكرارًا، فيمكنك وضع هذا المحتوى في partial view وتحميل هذه المحتويات من Partial View. بهذه الطريقة يمكنك منع تكرار الكود code duplication.

Partial Views هي ملفات cshtml. عادية ولا تختلف عن regular views إلا في الوظيفة التي تقوم بها. 

لنفرض هنا اننا بحاجة الى شاشة لإدخال مبلغ الفاتورة للطلاب، عند كل عملية او شراء. حيث يمكن استخدام هذه الشاشة من داخل نظام الجامعة، من خلال موقع الجامعة، من خلال تطبيق الموبايل، فبدلا من انشاء 3 صفحات لكل منصة (النظام، الموقع، الموبايل) سنقوم بإنشاء صفحة  Partial Views، بحيث يتم بناء هذه الصفحة مرة واحدة بالشكل المطلوب، ومن ثم استخدامها في أكثر من مكان. 

أضف Controller  جديد باسم PaymentController ثم أضف action داخلة باسم CardView 

الكود التالي يوضح ذلك: 


using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Controllers
{
    public class PaymentController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        public IActionResult CardView()
        {
            return View();
        }
    }
}
لإضافة View انقر يمين فوق CardView ثم اختر Add ➤ View ثم اختر Razor View ومن ثم اختر
 Create as Partial View  كما في الصورة في الاسفل


بهد هيك نضيف الى View الكود التالي:

@model PaymentModel
@{ 
    Layout = null;
}
<form method="post" asp-action="DoPayment">
    <div class="container">
        <main role="main" class="pb-3">
            <div class="row">
                <div class="col-md-12">
                    <div class="form-group">
                        <label>CustomerNo:</label>
                        <input class="form-control" asp-for="CardHolderName" />
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <div class="form-group">
                        <label>Card Number:</label>
                        <input class="form-control" asp-for="CardNumber" />
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label>Card Expiry Date:</label>
                        <input class="form-control" asp-for="CardExpiryDate" />
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label>CCV:</label>
                        <input class="form-control" asp-for="SecurityCode" />
                    </div>
                </div>
            </div>
            <button class="btn btn-primary" type="submit">Submit</button>
        </main>
    </div>
</form>
    

 تم تعريف حقول البطاقة في هذا View وهي :
  • CardHolderName
  • CardNumber
  • CardExpiryDate
  • SecurityCode
اضفنا الكود التالي في بداية View بهدغ عدم استخدام أي Layout فقط عرض الحقول المطلوبة لادخال بيانات البطاقة

@{ 
    Layout = null;
}

وتم ربط هذه الحقول مع PaymentModel.  طيب الان نحتاج انشاء هذا Model الخاص بتعريف حقول شاشة الدفع.
أضف ملف class جديد في مجلد Models باسم PaymentModel ثم أضف الكود التالي اليه: 

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Models
{
    public class PaymentModel
    {
        public string CardNumber { get; set; }
        public string Number { get; set; }
        public string CardHolderName { get; set; }
        public string SecurityCode { get; set; }
        public string ExpiryDateYear { get; set; }
        public string ExpiryDateMonth { get; set; }
        public string CardExpiryDate { get; set; }
        public string ExpiryDate { get; set; }
    }
}

ملاحظة: لم نقم باي Validation هنا لهذه الحقول. 
للمزيد حول Validation يمكن الانتقال الى الدرس Model Validation in ASP.NET Core

لنقم بتشغيل التطبيق بالانتقال الى الرابط
https://localhost:44382/payment/CardView
ستكون نتيجة View 


لاحظ ان هذا View لا يوجد به أي تصميم فقط عرض control الخاصة ببطاقة الدفع بحيث يمكن استخدامها في اي مكان في التطبيقات. 
لتطبيق هذا Partial View  داخل View آخر، نستخدم  Razor expression  التالي 
@await Html.PartialAsync()
لذا انتقل إلىView  المسمى StudentInfo  الموجود داخل مجلد Views / Students ثم أضف الكود التالي لاستدعاء partial view 
 @await Html.PartialAsync("CardView")
ستكون نتيجة التنفيذ في هذه الحالة خطأ الصورة أسفل توضح ذلك 


سبب هذا الخطأ هو ان Partial View  التي تم استدعاءها ليست في نفس المجلد Students لاحظ المربع الأحمر في الصورة في الأسفل، مكان البحث عن هذه View

لمعالجة هذا الخطأ يجب تعديل الكود الى تحديد المسار الصحيح الخاص ب CardView: 

@await Html.PartialAsync("~/Views/Payment/CardView.cshtml",Model.Payment)

لاحظ ايضا انه تم ارسال ModelPayment الى هذا View وذلك لانه تم تعريف هذا Partial View على استقبال هذا Model
بعد التعديل يكون الكود الخاص ب StudentInfo 


@model StudentsModel
@{
    ViewData["Title"] = "StudentInfo";
}
Welcome ,@ViewBag.UserName
<hr />
<p>Current Date: @Model.CurrentDate</p>
<hr />
<p>Current Year: @Model.CurrentDate.Year</p>
<h2>Student Info</h2>
<p>Customer No : @Model.CustomerNo</p>
<p>Full Name: @Model.FullName</p>
<p>Birthday: @Model.Birthday</p>
<p>Gender : @Model.Gender </p>
<p>Nationality : @Model.Nationality </p>
<p>Address : @Model.Address </p>
<p>UserName : @Model.UserName </p>
<p>Password : @Model.Password</p>
<p>Email : @Model.Email </p>
<p>Mobile : @Model.Mobile </p>
<hr />
<p>Payment Info</p>
@await Html.PartialAsync("~/Views/Payment/CardView.cshtml",Model.Payment)
ملاحظة: في هذه الحالة عندنا 2 View وكل واحد فيهم بستقبل model مختلف، اول استدعاء بكون ل StudentInfo الي بيتعامل مع Model باسم StudentsModel ، والثاني هو CardView الي بستقبل Model من نوع PaymentModel، ومشان هيك لازم نعدل على StudentsModel  واضافة PaymentModel  داخله. (الكود الخاص ب StudentsModel ):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Models
{
    public class StudentsModel
    {
        public string CustomerNo { get; set; }
        public string FullName { get; set; }
        public DateTime Birthday { get; set; }
        public int Gender { get; set; }
        public int Nationality { get; set; }
        public string Address { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Email { get; set; }
        public string Mobile { get; set; }
        public string Note { get; set; }
        public DateTime CurrentDate { get; set; }
        public PaymentModel Payment { get; set; }
    }
}
تمام الان دور نشغل التطبيق ونشوف النتيجة :
ادخل الرابط التالي :
واكيد بتكون النتيجة : 



 
هذا النوع الذي أنشأناه يسمى Strongly Typed   
تُستخدم Strongly Typed Partial Views  لنقل البيانات من Regular Views، أي أن لها نموذجها الخاص model. بالزبط مثل المثال السابق حيث ارسلنا model من نوع Payment. 
في حال كان Partial Views ليس من النوع Strongly Typed فهذا يعني انه لا يحتوي على Model ويتم استدعاءه عن طريق الامر: 

@await Html.PartialAsync("~/Views/Payment/CardView.cshtml")
مثال آخر على Strongly Typed
لنفرض وجود View يحتوي الكود التالي : 

@model List<string>
<div style="color:red">
    This is partial View:
    <ul>
        @foreach (string str in Model)
        {
            <li>@str</li>
        }
    </ul>
</div>
لاحظ أن هذا partial view يحتوي على model من النوع List، بعدها عملنا قراءة للقيم المرسلة باستخدام foreach loop  وبعدها عرضنا القيم داخل li tag عن طريق تكرارها جميعًا .
الآن لاستدعاء هذا partial view من StudentInfo view من خلال ارسال قيمة model أيضًا. يتم ذلك باستخدام 2nd parameter لـ @ Html.PartialAsync كما هو موضح أدناه:

@await Html.PartialAsync("~/Views/Payment/CardView.cshtml", new List<string> { "Classic ASP", "ASP.NET Web Forms", "ASP.NET MVC", "ASP.NET Core MVC" }) 
في هذا الكود ارسلنا مجموعة من string الى هذا Model