Skip to content

5. ویو و قالب آن

5.1. Introduction

بیایید به معماری یک برنامه ASP.NET MVC بازگردیم:

در فصل قبلی، ما بررسی کردیم که چگونه ASP.NET MVC اطلاعات را از درخواست [1] به یک اقدام [2a] در قالب مدلی که می‌توانست شامل محدودیت‌های اعتبارسنجی باشد، ارائه داد. این مدل به‌عنوان ورودی به اکشن ارائه شد و ما آن را مدل اکشن نامیدیم. اکنون به رایج‌ترین نتیجه یک عمل می‌پردازیم: نوع [ViewResult]، که متناظر با یک نمای V [3] به همراه مدل آن M [2c] است. این مدل به عنوان مدل نمای V نامیده می‌شود و نباید با مدل اقدام که به تازگی بررسی کردیم اشتباه گرفته شود. یکی ورودی به اقدام است و دیگری خروجی.

بیایید با ایجاد یک پروژه جدید، [Exemple-03] [1]، همچنان در همان سولوشن، از نوع پایه ASP.NET MVC شروع کنیم:

بیایید یک کنترلر به نام [First] [2] ایجاد کنیم. کد تولید شده برای این کنترلر به شرح زیر است:


using System.Web.Mvc;

namespace Exemple_03.Controllers
{
  public class FirstController : Controller
  {
    public ActionResult Index()
    {
      return View();
    }

  }
}
  • خطوط ۷–۱۰: یک اکشن [Index] ایجاد شده است. نوع نتیجه متد [Index] از کلاس [ActionResult] است که بیشتر نتایج ممکن یک اکشن از آن مشتق می‌شوند؛
  • خط ۹: متد [View] از کلاس [Controller] (خط ۵) یک نوع [ViewResult] را بازمی‌گرداند که از [ActionResult] مشتق شده است. این متد دارای چندین overload است. ما به چند مورد از آن‌ها نگاه خواهیم کرد. مورد اصلی به شرح زیر است:
 
  • پارامتر اول نام ویو است. اگر این پارامتر حذف شود، ویوی مورد استفاده، ویویی با همان نام اکشنی است که [ViewResult] را تولید می‌کند، و این ویو در پوشه [/Views/{controller}] جستجو خواهد شد، که در آن {controller} نام کنترلر است؛
  • دومین پارامتر، قالب نما است. اگر این پارامتر مشخص نشود، نما هیچ قالبی نخواهد داشت.

متد [Index] زیر:


public ActionResult Index()
    {
      return View();
}

به ویو [/Views/First/Index.cshtml] دستور می‌دهد که رندر شود. هیچ قالب (تمپلتی) را به آن پاس نمی‌دهد. بیایید [1] را در پوشه [/Views/First] بسازیم:

سپس، در داخل آن، بیایید نمای [Index] [2] را ایجاد کنیم:

ما نام ویو را [3] مشخص می‌کنیم. این به عنوان [4] ایجاد می‌شود. کد تولید شده به شرح زیر است:


@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        
    </div>
</body>
</html>

این کد استاندارد HTML است، به جز خطوط ۱ تا ۳ که به زبان C# نوشته شده‌اند. برنامه‌ای که نماها را مدیریت می‌کند، موتور نما (view engine) نامیده می‌شود. این مسئول پردازش هر چیزی است که HTML نباشد و تبدیل آن به HTML است. در نهایت، این چیزی است که به کلاینت ارسال خواهد شد. موتور ویو در اینجا [Razor] نامیده می‌شود. این امکان را فراهم می‌کند که کد C# در یک ویو گنجانده شود. [Razor] این کد C# را تفسیر کرده و از آن برای تولید کد HTML استفاده می‌کند. در اینجا چند قاعدهٔ پایه برای درج کد C# در یک ویو آورده شده است:

  • تغییر از HTML به C# زمانی رخ می‌دهد که با کاراکتر @ مواجه شویم (خط 1). اگر این کاراکتر یک بلوک کد را معرفی کند، باید از پرانتزهای منحنی استفاده شود (خطوط 1 و 3). اگر این کاراکتر متغیری را معرفی کند که می‌خواهید مقدار آن را بازیابی کنید، کافی است @variable را بنویسید؛
  • تغییر از C# به HTML زمانی رخ می‌دهد که کاراکتر < (خط ۵) مشاهده شود. گاهی اوقات، لازم است این تغییر را به صورت اجباری انجام داد، به خصوص هنگام درج متن ساده بدون تگ HTML در صفحه. در این حالت، از تگ <text> برای درج متن استفاده می‌شود: <text>متن ساده در اینجا</text>.

خط ۲ بالا نشان می‌دهد که نمای [Index] فاقد صفحهٔ اصلی است.

بیایید نما را به شرح زیر اصلاح کنیم:


@{
  Layout = null;
  string vue = "Index";
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Index</title>
</head>
<body>
  <div>
    <h3>Vue @vue</h3>
  </div>
</body>
</html>
  • خط ۳: یک متغیر C# را تعریف می‌کند؛
  • خط ۱۵: مقدار این متغیر را نمایش می‌دهد.

حال بیایید URL و [/First/Index] را فراخوانی کنیم:

 

کد دریافتی HTML به شرح زیر است:

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Index</title>
</head>
<body>
  <div>
    <h3>Vue Index</h3>
  </div>
</body>
</html>

این یک سند کاملاً HTML است. تمام کد C# ناپدید شده است.

5.2. برای ارسال اطلاعات به نما از [ViewBag] استفاده کنید

ما یک اکشن جدید به نام [Action01] ایجاد می‌کنیم که با ویوی [Action01.cshtml] مرتبط است:

عمل [Action01] به شرح زیر است:


    // اقدام ۰۱
    public ViewResult Action01()
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      return View();
}
  • خط ۴: از خاصیت [ViewBag] کنترل‌کننده استفاده می‌شود. این یک شیء پویا است که می‌توان به آن خاصیت‌ها افزود، همانطور که در خط ۴ نشان داده شده است. ویژگی متمایز این شیء این است که برای نما (view) نیز قابل دسترسی است. بنابراین این روشی برای ارسال اطلاعات به آن است؛
  • خط ۵: نمای پیش‌فرض اکشن درخواست می‌شود. این نما [/First/Action01.cshtml] است. هیچ قالبی به آن ارسال نمی‌شود.

نما [Action01.cshtml] به شرح زیر است:


@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action01</title>
</head>
<body>
  <div>
    <h4>@ViewBag.info</h4>
  </div>
</body>
</html>
  • خط ۱۴: ویژگی [ViewBag.info] نمایش داده می‌شود.

بیایید آن را آزمایش کنیم. ما URL و [/First/Action01] را درخواست می‌کنیم:

 

5.3. استفاده از یک مدل با نوع‌دهی قوی برای ارسال اطلاعات به نما

روش قبلی این عیب را دارد که اجازه نمی‌دهد خطاها قبل از اجرا شناسایی شوند. بنابراین، اگر ویو [Action01.cshtml] از کد استفاده کند


<h4>@ViewBag.Info</h4>

یک خطا رخ خواهد داد زیرا خاصیت [Info] وجود ندارد. موردی که توسط اکشن [Action01] ایجاد می‌شود، [info] نام دارد. بنابراین می‌توان از یک مدل با نوع‌بندی قوی برای جلوگیری از این مشکل استفاده کرد.

در یکی از مثال‌های بررسی‌شده قبلاً، اقدام به شرح زیر بود:


    // اقدام ۱۰
    public ContentResult Action10(ActionModel03 modèle)
    {
      string erreurs = getErrorMessagesFor(ModelState);
      string texte = string.Format("email={0}, jour={1}, info1={2}, info2={3}, info3={4}, erreurs={5}",
        modèle.Email, modèle.Jour, modèle.Info1, modèle.Info2, modèle.Info3, erreurs);
      return Content(texte, "text/plain", Encoding.UTF8);
}

اقدام [Action10] شش مورد اطلاعات (ایمیل، روز، Info1، Info2، Info3، خطاها) را به صورت یک رشته به کلاینت خود ارسال کرد. ما این اطلاعات را از طریق یک مدل نما به نام [ViewModel01] ارسال خواهیم کرد. از آنجا که این مدل اطلاعات را از [ActionModel03] مجدداً استفاده می‌کند، آن را از آن کلاس مشتق خواهیم کرد.

ما با کپی کردن [ActionModel03] از پروژه [Exemple-02] به پروژه فعلی [Exemple-03] شروع می‌کنیم:

و فضای نام آن را تغییر می‌دهیم تا با فضای نام پروژه [Exemple-03] مطابقت داشته باشد:


using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
  public class ActionModel03
  {
    [Required(ErrorMessage = "Le paramètre email est requis")]
    [EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")]
    public string Email { get; set; }

    [Required(ErrorMessage = "Le paramètre jour est requis")]
    [RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]
    public string Jour { get; set; }

    [Required(ErrorMessage = "Le paramètre info1 est requis")]
    [MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")]
    public string Info1 { get; set; }

    [Required(ErrorMessage = "Le paramètre info2 est requis")]
    [MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")]
    public string Info2 { get; set; }

    [Required(ErrorMessage = "Le paramètre info3 est requis")]
    [MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
    [MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
    public string Info3 { get; set; }
  }
}
  • خط ۲: فضای نام جدید؛

سپس کلاس [ViewModel01] را ایجاد می‌کنیم:

کد برای [ViewModel01] به شرح زیر است:


namespace Exemple_03.Models
{
  public class ViewModel01 : ActionModel03
  {
    public string Erreurs { get; set; }
  }
}
  • خط ۳: کلاس از [ActionModel03] ارث می‌برد و بنابراین ویژگی‌های [Email, Jour, Info1, Info2, Info3] را نیز به ارث می‌برد؛
  • خط ۵: ویژگی [Erreurs] به آن اضافه می‌شود.

اکنون اکشن [Action02] را می‌نویسیم که:

  • قالب اکشن [ActionModel03] را به‌عنوان ورودی می‌گیرد؛
  • و قالب نما [ViewModel01] را بازمی‌گرداند.

کد آن به شرح زیر است:


    // اقدام02
    public ViewResult Action02(ActionModel03 modèle)
    {
      string erreurs = getErrorMessagesFor(ModelState);
      return View(new ViewModel01(){Email=modèle.Email, Jour=modèle.Jour, Info1=modèle.Info1, Info2=modèle.Info2, Info3=modèle.Info3, Erreurs=erreurs});
}
  • خط ۱: [Action02] قالب اقدام [ActionModel03] را دریافت می‌کند. این تابع نتیجه‌ای از نوع [ViewResult] را برمی‌گرداند؛
  • خط ۴: خطاهای مربوط به قالب اقدام [ActionModel03] در رشته [erreurs] جمع‌آوری می‌شوند. متد [getErrorMessagesFor] در صفحه 65 توضیح داده شده و در کنترلر [First] پروژه جدید گنجانده شده است؛
  • خط ۵: متد [View] با یک پارامتر فراخوانی می‌شود. این مدل نما (view model) است. خود نما (view) مشخص نشده است. بنابراین، از نمای پیش‌فرض [/Views/First/Action02] استفاده خواهد شد. مدل نما [ViewModel01] با پنج مورد اطلاعات از مدل اقدام [ActionModel03] و اطلاعات [erreurs] که در خط ۴ ساخته شده است، نمونه سازی و مقداردهی اولیه می‌شود.

اکنون نما [/First/Action02.cshtml] را می‌سازیم:

کد آن به شرح زیر است:


@model Exemple_03.Models.ViewModel01
@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action02</title>
</head>
<body>
  <h3>Informations du modèle de vue</h3>
  <ul>
    <li>Email : @Model.Email</li>
    <li>Jour : @Model.Jour</li>
    <li>Info1 : @Model.Info1</li>
    <li>Info2 : @Model.Info2</li>
    <li>Info3 : @Model.Info3</li>
    <li>Erreurs : @Model.Erreurs</li>
  </ul>
</body>
</html>
  • ویژگی جدید در خط ۱ قرار دارد. نشانه [@model] نوع قالب نما را مشخص می‌کند. این قالب سپس توسط نشانه [@Model] (خطوط ۱۶–۲۱) ارجاع داده می‌شود؛
  • خطوط ۱۵–۲۲: اطلاعات مدل در یک لیست نمایش داده می‌شود.

بیایید چند مثال از نحوه اجرای عمل [Action02] را ببینیم.

ابتدا، بدون هیچ پارامتری:

 

سپس با پارامترهای نادرست:

سپس با پارامترهای صحیح:

در این مثال، قالب نما [ViewModel01] اطلاعات خود را از قالب اقدام [ActionModel03] می‌گیرد. این امر اغلب اتفاق می‌افتد. سپس می‌توان از یک قالب واحد به عنوان هم قالب اقدام و هم قالب نما استفاده کرد. ما یک قالب جدید، [ActionModel04]، ایجاد می‌کنیم:

  

که به شرح زیر خواهد بود:


using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Exemple_03.Models
{
  [Bind(Exclude="Erreurs")]
  public class ActionModel04
  {
    // ---------------------- اقدام --------------------------------
    [Required(ErrorMessage = "Le paramètre email est requis")]
    [EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")]
    public string Email { get; set; }

    [Required(ErrorMessage = "Le paramètre jour est requis")]
    [RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]
    public string Jour { get; set; }

    [Required(ErrorMessage = "Le paramètre info1 est requis")]
    [MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")]
    public string Info1 { get; set; }

    [Required(ErrorMessage = "Le paramètre info2 est requis")]
    [MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")]
    public string Info2 { get; set; }

    [Required(ErrorMessage = "Le paramètre info3 est requis")]
    [MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
    [MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
    public string Info3 { get; set; }

    // ---------------------- نما --------------------------------
    public string Erreurs { get; set; }
  }
}
  • خطوط ۸–۲۸: مدل عملیاتی به همراه محدودیت‌های یکپارچگی آن. این فیلدها همچنین بخشی از نما را تشکیل خواهند داد؛
  • خط ۳۱: یک ویژگی اختصاصی برای مدل نما. این ویژگی با استفاده از حاشیه‌نویسی در خط ۵ از مدل اقدام حذف شده است.

ما اقدام جدید زیر را ایجاد می‌کنیم، [Action03]:


    // Action03
    public ViewResult Action03(ActionModel04 modèle)
    {
      modèle.Erreurs = getErrorMessagesFor(ModelState);
      return View(modèle);
}
  • خط ۲: [Action03] قالب اقدام از نوع [ActionModel04] را دریافت می‌کند؛
  • خط ۵: و همین قالب را به‌عنوان قالب نما بازمی‌گرداند؛
  • خط ۴: تکمیل‌شده با اطلاعات [Erreurs];

تنها کاری که باقی مانده، ایجاد نما [/First/Action03.cshtml] است:

  • در [1]: در کد مربوط به [Action03]، سپس [Ajouter une vue]، کلیک راست کنید؛
  • به [2]: نام پیش‌فرض نما؛
  • در [3]: مشخص کنید که در حال ایجاد یک نمای با نوع‌بندی قوی هستید؛
  • در [4]: کلاس صحیح را از لیست کشویی انتخاب کنید، در این مورد کلاس [ActionModel04
  • در [5]: نمای ایجادشده.

ما به ویوی [Action03] همان کد ویوی [Action02] را می‌دهیم. تنها قالب ویو (خط ۱) و عنوان صفحه (خط ۱۱) تغییر می‌کنند:


@model Exemple_03.Models.ActionModel04
@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action03</title>
</head>
<body>
  <h3>Informations du modèle de vue</h3>
  <ul>
    <li>Email : @Model.Email</li>
    <li>Jour : @Model.Jour</li>
    <li>Info1 : @Model.Info1</li>
    <li>Info2 : @Model.Info2</li>
    <li>Info3 : @Model.Info3</li>
    <li>Erreurs : @Model.Erreurs</li>
  </ul>
</body>
</html>

اکنون بیایید اکشن [Action03] را بدون هیچ پارامتری فراخوانی کنیم:

 

نتایج مانند قبل هستند. معمولاً از یک مدل یکسان برای هر دو مدل اقدام و نما استفاده می‌شود، زیرا مدل نما اغلب از اطلاعات مدل اقدام استفاده مجدد می‌کند. بنابراین از یک مدل جامع‌تر استفاده می‌شود که هم توسط مدل اقدام و هم توسط نمای تولید شده توسط آن قابل استفاده است. باید دقت شود که هرگونه اطلاعاتی که به مدل اکشن تعلق ندارد، از پیوند داده‌ها حذف شود. در غیر این صورت، یک کاربر آگاه می‌تواند بدون اطلاع ما، بخش‌هایی از مدل ویو را مقداردهی اولیه کند.

5.4. [Razor] – شروع کار

اکنون برخی از عناصر نماها [Razor]، عمدتاً دستورالعمل‌های foreach و if را ارائه خواهیم داد.

فرض کنید می‌خواهیم فهرستی از افراد را در جدولی به نام HTML نمایش دهیم. قالب نما می‌تواند به شکل زیر باشد [ViewModel02]:


namespace Exemple_03.Models
{
  public class ViewModel02
  {
    public Personne[] Personnes { get; set; }
    public ViewModel02()
    {
      Personnes = new Personne[] { new Personne { Nom = "Pierre", Age = 44 }, new Personne { Nom = "Pauline", Age = 12 } };
    }
  }

  public class Personne
  {
    public string Nom { get; set; }
    public int Age { get; set; }
  }
}
  • نما (view) مدل، کلاس [ViewModel02]، خطوط ۳–۱۰ است؛
  • خط ۵: مدل دارای آرایه‌ای از افراد از نوع [Personne] است که در خطوط ۱۲–۱۶ تعریف شده است؛
  • خطوط ۶–۱۰: سازنده مدل خاصیت [Personnes] از خط ۵ را با آرایه‌ای از دو نفر مقداردهی اولیه می‌کند.

عمل تولید این قالب به‌عنوان خروجی به شرح زیر خواهد بود: [Action04]:


    // Action04
    public ViewResult Action04()
    {
      return View(new ViewModel02());
}
  • خط ۲: اکشن هیچ قالب ورودی ندارد؛
  • خط ۴: به نمای پیش‌فرض خود، نمونه‌ای از قالب [ViewModel02] که همین حالا تعریف کرده‌ایم، سوئیچ می‌کند.

ویوی [Action04.cshtml] مدل [ViewModel02] را نمایش خواهد داد:

کد نما [Action04.cshtml] به شرح زیر است:


@model Exemple_03.Models.ViewModel02
@using Exemple_03.Models

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action04</title>
</head>
<body>
  <table border="1">
    <thead>
      <tr>
        <th>Nom</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody>
      @foreach (Personne p in Model.Personnes)
      {
        <tr>
          <td>@p.Nom</td>
          <td>@p.Age</td>
        </tr>
      }
    </tbody>
  </table>
</body>
</html>
  • خط ۱: قالب نما؛
  • خط ۲: وارد کردن فضای نام برای کلاس [Personne] که در خط ۲۴ استفاده شده است؛
  • خطوط ۱۶–۳۲: آرایه HTML، که افراد موجود در مدل را نمایش می‌دهد؛
  • خط ۲۴: شروع کد C# با کاراکتر @ مشخص می‌شود. دستور [foreach] به صورت حلقه‌ای از میان تمام افراد موجود در مدل عبور می‌کند؛
  • خطوط ۲۶–۲۷: کاراکتر < کد C# را پایان داده و کد HTML را آغاز می‌کند. سپس، بار دیگر، کاراکتر @ به C# بازمی‌گردد تا نام شخص را بنویسد. سپس، بار دیگر، کاراکتر < به حالت HTML بازمی‌گردد؛
  • خط ۲۸: سن شخص نوشته می‌شود.

اجرای عمل [Action04] نتیجه زیر را تولید می‌کند:

 

سایر عناصر یک نما می‌توانند از یک مجموعه پر شوند: فهرست‌ها (کشویی یا غیرکشویی)، دکمه‌های رادیویی و چک‌باکس‌ها. بیایید مثال جدید زیر را در نظر بگیریم که یک فهرست کشویی را نمایش می‌دهد.

قالب [ViewModel05] به شرح زیر خواهد بود:


namespace Exemple_03.Models
{
  public class ViewModel05
  {
    public Personne2[] Personnes { get; set; }
    public int SelectedId { get; set; }

    public ViewModel05()
    {
      Personnes = new Personne2[] { 
        new Personne2 { Id = 1, Prénom = "Pierre", Nom = "Martino" }, 
        new Personne2 { Id = 2, Prénom = "Pauline", Nom = "Pereiro" }, 
        new Personne2 { Id = 3, Prénom = "Jacques", Nom = "Alfonso" } };
      SelectedId = 2;
    }
  }

  public class Personne2
  {
    public int Id { get; set; }
    public string Nom { get; set; }
    public string Prénom { get; set; }
  }
}
  • خط ۱۸: یک کلاس [Personne2] با سه ویژگی؛
  • خط ۳: قالب [ViewModel05] برای نما؛
  • خط ۵: فهرست افرادی که باید در لیست کشویی در قالب [Prénom Nom] نمایش داده شوند؛
  • خط ۶: [Id] مربوط به فردی که باید از لیست کشویی انتخاب شود؛
  • خطوط ۸–۱۶: سازنده که آرایه‌ای از سه نفر (خطوط ۱۰–۱۳) ایجاد می‌کند و [Id] فرد را که باید به‌عنوان انتخاب‌شده نمایش داده شود، تعیین می‌کند.

نما [Action05.cshtml] این قالب را نمایش خواهد داد:

کد آن به شرح زیر است:


@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action05</title>
</head>
<body>
  <select>
    @foreach (Personne2 p in Model.Personnes)
    {
      string selected = "";
      if (p.Id == Model.SelectedId)
      {
        selected = "selected=\"selected\"";
      }
      <option value="@p.Id" @selected>@p.Prénom @p.Nom</option>
    }
  </select>
</body>
</html>

ویژگی‌های فهرست کشویی HTML در بخش 2.5.2.6 تشریح شدند. برای مرور:

ترکیبی
<select size="1" name="cmbValeurs">
<option value="1">انتخاب۱</option>
<option selected="selected" value="2">option2</option>
<option value="3">option3</option>
</select>
 
برچسب HTML
<select size=".." name="..">
<option [selected="selected"] value="v">...</option>
...
</select>
متن بین <option>...</option> را نمایش می‌دهد
ویژگی‌ها
name="cmbValeurs": نام کنترل.
size="1": تعداد موارد قابل مشاهده لیست. size="1" لیست را معادل یک کادر ترکیبی می‌کند.
selected="selected": اگر این کلمه کلیدی برای یک آیتم لیست وجود داشته باشد، آن آیتم در لیست به صورت انتخاب‌شده ظاهر می‌شود. در مثال بالا، آیتم لیست choix2 هنگام اولین نمایش، به عنوان آیتم انتخاب‌شده در کادر ترکیبی ظاهر می‌شود.
value="v": اگر آیتم توسط کاربر انتخاب شود، این مقدار، [v]، به سرور ارسال می‌شود. اگر این ویژگی وجود نداشته باشد، متنی که نمایش داده شده و انتخاب شده است به سرور ارسال می‌شود.

کد در خطوط 17–25 تگ‌های <option> را تولید می‌کند که درون تگ <select> در خط 16 قرار می‌گیرند.

  • خط ۱۷: فهرست افراد در قالب به‌صورت پشت سر هم بررسی می‌شود؛
  • خط ۲۰: بررسی می‌کنیم که آیا فرد فعلی همان فردی است که باید انتخاب شود. اگر چنین باشد، متن selected="selected" را برای درج در تگ <option> آماده می‌کنیم؛
  • خط 24: تگ <option> نوشته می‌شود.

بیایید این عمل را [Action05] بنامیم:

  • در [1,2]، افراد به شکل [Prénom Nom] نمایش داده می‌شوند؛
  • در [1,2]، فرد منتخب کسی است که در آن [Id] برابر با ۲ باشد.

حال بیایید کد منبع HTML صفحهٔ بالا را بررسی کنیم:


<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action05</title>
</head>
<body>
  <select>
      <option value="1" >Pierre Martino</option>
      <option value="2" selected=&quot;selected&quot;>Pauline Pereiro</option>
      <option value="3" >Jacques Alfonso</option>
  </select>
</body>
</html>
  • خطوط ۱۰–۱۲: سه تگ <option> تولید شده توسط کد [Razor];
  • خط ۱۱: در واقع فردی که از [Id]=2 انتخاب شده است.

دو مثال بالا کافی است. هنگام نوشتن یک نمای [Razor]، باید در برابر وسوسهٔ قرار دادن منطق در آن مقاومت کرد. کد C# به ما این امکان را می‌دهد. با این حال، در مدل MVC، منطق باید در اکشن یا در لایه‌های پایین‌تر ([Metier, DAO]) باشد، اما نه در ویو. حتی با پایبندی به الگوی MVC، ممکن است در نهایت با منطق زیادی در ویو برای محاسبه مقادیر میانی مواجه شوید. این ممکن است نشان دهد که الگوی مورد استفاده به اندازه کافی با جزئیات نیست. این الگو باید شامل مقادیر نهایی مورد نیاز ویو باشد تا ویو مجبور نباشد آنها را خود محاسبه کند. یک ویوی خوب، ویویی است که حداقل منطق را داشته باشد و ساختار HTML آن واضح باقی بماند. اگر کد C# زیادی وارد شود، ساختار HTML می‌تواند غیرقابل خواندن شود.

در مثال بالا، ممکن است کاربر از لیست کشویی استفاده کند و ما بخواهیم بدانیم کدام شخص را انتخاب کرده است. برای این کار به یک فرم نیاز داریم.

5.5. فرم‌ها – شروع کار

فرم ارائه‌شده به کاربر به شرح زیر خواهد بود:

 

قالب نما همان قالب [ViewModel05] است که قبلاً استفاده شده است. اکشنی که این نما را نمایش می‌دهد به شرح زیر خواهد بود:


    // Action06-GET
    [HttpGet]
    public ViewResult Action06()
    {
      return View("Action06Get",new ViewModel05());
}
  • خط ۲: این اقدام تنها با دستوری از نوع HTTP GET قابل اجرا است؛
  • خط ۵: نمای [/First/Action06Get.cshtml] با استفاده از یک نمونه از نوع [ViewModel05] به‌عنوان الگو نمایش داده خواهد شد.

نما [/First/Action06Get.cshtml] به شرح زیر خواهد بود:


@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action06-GET</title>
</head>
<body>
  <h3>Action06 - GET</h3>
  <p>Choisissez une personne</p>
  <form method="post" action="/First/Action06">
    <select name="personneId">
      @foreach (Personne2 p in Model.Personnes)
      {
        string selected = "";
        if (p.Id == Model.SelectedId)
        {
          selected = "selected=\"selected\"";
        }
        <option value="@p.Id" @selected>@p.Prénom @p.Nom</option>
      }
    </select>
    <input name="valider" type="submit" value="Valider" />
  </form>
</body>
</html>

ویژگی‌های اصلی جدید به شرح زیر است:

  • خط ۱۸: برای اینکه مرورگر اطلاعات واردشده توسط کاربر را ارسال کند، به یک فرم نیاز داریم. این فرم با تگ <form> در خطوط ۱۸ و ۳۱ تعریف شده است.

برچسب <form> در بخش 2.5.2.1 معرفی شد. بیایید ویژگی‌های آن را مرور کنیم:

form

<form method="post" action="FormulairePost.aspx">
برچسب HTML
<form name="..." method="..." action="...">...</form>
ویژگی‌ها
name="frmexample": نام فرم – اختیاری
method="..." : متدی که توسط مرورگر برای ارسال مقادیر جمع‌آوری‌شده در فرم به سرور وب استفاده می‌شود.
action="..." : URL که مقادیر جمع‌آوری‌شده در فرم به آن ارسال می‌شوند.
یک فرم وب در میان برچسب‌های <form>...</form> قرار می‌گیرد. این فرم ممکن است یک نام (name="xx") داشته باشد. این موضوع در مورد تمام کنترل‌هایی که در داخل یک فرم یافت می‌شوند نیز صدق می‌کند. هدف یک فرم، جمع‌آوری اطلاعاتی است که کاربر از طریق صفحه‌کلید یا ماوس وارد می‌کند و ارسال آن به URL وب سرور است. کدام یک؟ همان موردی که در ویژگی action="URL" به آن ارجاع داده شده است. اگر این ویژگی وجود نداشته باشد، اطلاعات به URL سندِ حاوی فرم ارسال خواهد شد. یک کلاینت وب می‌تواند از دو روش مختلف به نام‌های POST و GET برای ارسال داده‌ها به یک سرور وب استفاده کند. ویژگی method="méthode"، که در آن method روی GET یا POST تنظیم شده است، در تگ <form> به مرورگر می‌گوید که از کدام روش برای ارسال اطلاعات جمع‌آوری‌شده در فرم به URL مشخص‌شده توسط ویژگی action="URL" استفاده کند. وقتی ویژگی method مشخص نشده باشد، روش GET به‌طور پیش‌فرض استفاده می‌شود.
  • خط ۱۸: می‌بینیم که مقادیر فرم از طریق یک فرمان HTTP POST به URL [/First/Action06] ارسال خواهند شد؛
  • خط ۳۰: یک فرم باید دارای دکمه‌ای از نوع [submit] باشد. این دکمه ارسال مقادیر واردشده به URL را که توسط ویژگی [action] تگ <form> مشخص شده است، فعال می‌کند.

مرورگر دقیقاً چه چیزی را ارسال خواهد کرد وقتی کاربر روی دکمه [Valider] کلیک می‌کند؟ این موضوع در بخش 2.5.3.1 توضیح داده شده است. بیایید آنچه گفته شد را مرور کنیم:


کنترل HTML


نمایشی


مقادیر بازگشتی

<input type="radio" value="Yes" name="R1"/>بله
<input type="radio" name="R1" value="No" checked="checked"/>خیر
R1=بله
- مقدار ویژگی value دکمه رادیویی که توسط کاربر انتخاب شده است.
<input type="checkbox" name="C1" value="one"/>1
<input type="checkbox" name="C2" value="two" checked="checked"/>2
<input type="checkbox" name="C3" value="three"/
C1=یک
C2=دو
- مقادیر ویژگی‌های value برای چک‌باکس‌هایی که توسط کاربر تیک خورده‌اند
<input type="text" name="txtSaisie" size="20" value="چند کلمه"/>
txtInput=وب+برنامه‌نویسی
- متنی که کاربر در فیلد ورودی تایپ کرده است. فاصله‌ها با علامت + جایگزین شده‌اند
<input type="password" name="txtMdp" size="20" value="unMotDePasse"/>
txtMdp=thisissecret
- متنی که کاربر در فیلد ورودی تایپ کرده است
<textarea rows="2" name="areaSaisie" cols="20">
line1
خط ۲
line3
</textarea>
input-area=مبانی+%0D%0A
وب+برنامه‌نویسی
- متنی که کاربر در فیلد ورودی تایپ می‌کند. %OD%OA نشانگر پایان خط است. فاصله‌ها با علامت + جایگزین شده‌اند
<select size="1" name="cmbValeurs">
<option value='1'>انتخاب1</option>
<option selected="selected" value='2'>option2</option>
<option value='3'>option3</option>
</select>
cmbValues=3
- ویژگی [value] عنصری که توسط کاربر انتخاب شده است
<select size="3" name="lst1">
<option selected="selected" value='1'>list1</option>
<option value='2'>list2</option>
<option value='3'>list3</option>
<option value='4'>list4</option>
<option value='5'>list5</option>
</select>
lst1=3
- ویژگی [value] عنصری که توسط کاربر انتخاب شده است
<select size="3" name="lst2" multiple="multiple">
<option selected="selected" value='1'>list1</option>
<option value='2'>list2</option>
<option selected="selected" value='3'>list3</option>
<option value='4'>list4</option>
<option value='5'>list5</option>
</select>
lst2=1
lst2=3
- [value] ویژگی‌های عناصری که توسط کاربر انتخاب شده‌اند
<input type="submit" value="ارسال" name="cmdRenvoyer"/>
 
cmdResend=Submit
- نام و ویژگی value دکمهٔ مورد استفاده برای ارسال داده‌های فرم به سرور
<input type="hidden" name="secret" value="uneValeur"/>
 
secret=aValue
- ویژگی value از فیلد مخفی

در فرم ما، دو تگ وجود دارد که قادر به ارسال یک مقدار هستند:


    <select name="personneId">
...
</select>

و


<input name="valider" type="submit" value="Valider" />

اگر کاربر شخص شماره ۲ را انتخاب کند، مقادیر به فرمت زیر ارسال خواهند شد:

personneId=2&valider=Valider

نام‌های پارامترها با ویژگی‌های [name] تگ‌هایی که تحت تأثیر POST قرار دارند، مطابقت دارند. بدون این ویژگی، تگ‌ها هیچ مقداری ارسال نمی‌کنند. بنابراین، در مثال بالا می‌توانیم ویژگی name="valider" را از دکمه [submit] حذف کنیم. مقدار ارسالی، ویژگی [value] دکمه است. در این مورد، ما به این اطلاعات علاقه‌ای نداریم. گاهی اوقات فرم‌ها دارای چندین دکمه از نوع [submit] هستند. در چنین مواردی، دانستن اینکه کدام دکمه کلیک شده است، مهم است. بنابراین، ما ویژگی [name] را به دکمه‌های مختلف اختصاص می‌دهیم.

تگ <select> از یک دنباله از تگ‌های <option> تشکیل شده است:


    <select name="personneId">
        <option value="1" >Pierre Martino</option>
        <option value="2" selected=&quot;selected&quot;>Pauline Pereiro</option>
        <option value="3" >Jacques Alfonso</option>
</select>

ارزش ویژگی [value]ِ گزینه‌ی انتخاب‌شده ارسال می‌شود. اگر این ویژگی وجود نداشته باشد، متنی که توسط گزینه نمایش داده می‌شود – برای مثال، [Pierre Martino] – ارسال می‌شود.

رشته

personneId=2&valider=Valider

به URL [/First/Action06] زیر ارسال خواهد شد:


    // Action06-POST
    [HttpPost]
    public ViewResult Action06(ActionModel06 modèle)
    {
      return View("Action06Post",modèle);
}

شاید به یاد داشته باشید که ما قبلاً یک اقدام [Action06] داشتیم:


    // Action06-GET
    [HttpGet]
    public ViewResult Action06()
    {
      return View("Action06Get",new ViewModel05());
}

ممکن است دو اقدام با نام یکسان داشته باشیم، به شرط آنکه هر دو فرمان‌های یکسانی را پردازش نکنند HTTP:

  • [Action06] در خط ۳ یک POST (خط ۲) را پردازش می‌کند؛
  • [Action06] در خط c، GET (خط b) را پردازش می‌کند.

عمل [Action06] که POST را مدیریت می‌کند، رشته پارامتر زیر را دریافت خواهد کرد:

personneId=2&valider=Valider

ما به یک قالب اقدام نیاز داریم تا این مقادیر را در بر بگیرد. این قالب [ActionModel06] زیر خواهد بود:


using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
  public class ActionModel06
  {
    [Required(ErrorMessage = "Le paramètre [personneId] est requis")]
    public int PersonneId { get; set; }

    [Required(ErrorMessage = "Le paramètre [valider] est requis")]
    public string Valider { get; set; }
  }
}

اقدام [Action06] این قالب را دریافت کرده و بدون تغییر آن را به نمای بعدی [Action06Post] ارسال می‌کند (خط ۵ اقدام):


@model Exemple_03.Models.ActionModel06

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action06Post</title>
</head>
<body>
  <h3>Action06 - POST</h3>
  Valeurs postées :
  <ul>
    <li>ID de la personne sélectionnée : @Model.PersonneId</li>
    <li>Commande utilisée : @Model.Valider</li>
  </ul>
</body>
</html>

قالب در خطوط ۱۸ و ۱۹ نمایش داده می‌شود.

بیایید به یک مثال نگاه کنیم:

در [1]، شخص سوم از [Id] که برابر با ۳ است، انتخاب می‌شود. در [2]، فرم ارسال می‌شود. در [3]، مقادیر دریافت می‌شوند. در [4,5]، می‌توانیم ببینیم که همان URL فراخوانده شده است، یکی توسط GET [4]، دیگری توسط POST و [5]. این در URL قابل مشاهده نیست.

در نمایی که پس از POST نمایش داده می‌شود، ممکن است ترجیح داده شود که nom و prénom برای شخص انتخاب‌شده به جای شماره او نمایش داده شود. بنابراین نمای POST و قالب آن باید به‌روزرسانی شوند.

ما یک اکشن [Action07] برای مدیریت این سناریو ایجاد می‌کنیم. این اکشن باید از جلسهٔ کاربر برای ذخیرهٔ فهرست افراد استفاده کند. ما از مدلی که در بخش 4.10 مورد بحث قرار گرفته است پیروی خواهیم کرد، که امکان درج داده‌های دامنه از [Application] و [Session] در مدل اکشن را فراهم می‌کند.

مدل جلسه کلاس زیر خواهد بود، [SessionModel]:


namespace Exemple_03.Models
{
  public class SessionModel
  {
    public Personne2[] Personnes { get; set; }
  }
}
  • خط ۲: جلسه لیست افرادی را که در لیست کشویی نمایش داده می‌شوند، ذخیره خواهد کرد؛

ما باید نوع قبلی، [SessionModel]، را به یک بایندر که آن را [SessionModelBinder] می‌نامیم، لینک کنیم. این همان چیزی است که در صفحهٔ ۸۲ توضیح داده شده است:

  

using System.Web.Mvc;

namespace Exemple_03.Infrastructure
{
  public class SessionModelBinder : IModelBinder
  {
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      // داده‌های دامنه را بازمی‌گرداند [Session]
      return controllerContext.HttpContext.Session["data"];
    }
  }
}

ارتباط بین قالب [SessionModel] و نسخه‌های قبلی و بعدی آن، binder و [SessionModelBinder]، در [Global.asax] برقرار شده است:


public class MvcApplication : System.Web.HttpApplication
  {
    protected void Application_Start()
    {
      ...

      // بسته‌بندهای مدل
      ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
    }
    // جلسه
    public void Session_Start()
    {
      Session["data"] = new SessionModel();
    }
  }
  • خط ۸: مدل در [Application_Start] به بایندر خود متصل می‌شود؛
  • خط ۱۳: یک نمونه از نوع [SessionModel] به جلسه مرتبط با کلید [data] اضافه می‌شود.

پس از انجام این کار، اقدام [Action07] به شرح زیر است:


    // Action07-GET
    [HttpGet]
    public ViewResult Action07(SessionModel session)
    {
      ViewModel05 modèleVue = new ViewModel05();
      session.Personnes= modèleVue.Personnes;
      return View("Action07Get", modèleVue);
}
  • خط ۳: عمل یک نوع [SessionModel] را بازیابی می‌کند، یعنی داده‌های دامنه [Session] مرتبط با کلید [data
  • خط ۵: قالب نما ساخته می‌شود؛
  • خط ۶: آرایه افراد در جلسه قرار داده می‌شود. این آرایه در پرس‌وجوی بعدی برای POST مورد نیاز خواهد بود. پروتکل HTTP یک پروتکل بدون حالت است. برای حفظ داده‌ها بین پرس‌وجوها باید از یک جلسه استفاده شود. یک جلسه به کاربر خاصی اختصاص دارد و توسط وب‌سرور مدیریت می‌شود؛
  • خط ۷: نمای [Action07Get.cshtml] نمایش داده می‌شود. به شرح زیر است:

@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models
...
<body>
  <h3>Action07 - GET</h3>
  <p>Choisissez une personne</p>
  <form method="post" action="/First/Action07">
....
  </form>
</body>
</html>

این دقیقاً مشابه نمای [Action06Get.cshtml] است که قبلاً مورد بحث قرار گرفت. تفاوت اصلی در خط ۷ است: نمای URL که مقادیر فرم به آن ارسال خواهد شد. این موارد توسط اقدام بعدی، [Action07]، پردازش خواهند شد:


    // Action07-POST
    [HttpPost]
    public ViewResult Action07(SessionModel session, ActionModel06 modèle)
    {
      Personne2 personne = session.Personnes.Where(p => p.Id == modèle.PersonneId).First<Personne2>();
      string strPersonne = string.Format("{0} {1}", personne.Prénom, personne.Nom);
      return View("Action07Post", (object)strPersonne);
}
  • خط ۳: مقادیر ارسال‌شده در قالب اقدام [ActionModel06] قرار می‌گیرند، که قبلاً (در زیر) استفاده شده است:

using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
  public class ActionModel06
  {
    [Required(ErrorMessage = "Le paramètre [personneId] est requis")]
    public int PersonneId { get; set; }

    [Required(ErrorMessage = "Le paramètre [valider] est requis")]
    public string Valider { get; set; }
  }
}
  • خط ۳: پارامتر اول داده‌های دامنه [Session] است که با کلید [data] مرتبط است؛
  • خط ۵: یک پرس‌وجو LINQ شخص دارای [Id] که ارسال شده است را بازیابی می‌کند؛
  • خط ۶: رشتهٔ کاراکتری که باید توسط نما [Action07Post] (خط ۸) نمایش داده شود، ساخته می‌شود؛
  • خط ۷: برای فراخوانی سازندهٔ صحیح [View]، نوع [string] باید به [object] تبدیل شود.

ویو [Action07Post.cshtml] به شرح زیر است:


@model string

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action07-Post</title>
</head>
<body>
  <h3>Action07-POST</h3>
  Vous avez sélectionné [@Model].
</body>
</html>
  • خط ۱: قالب از نوع [string] است؛
  • خط ۱۶: رشتهٔ کاراکتری نمایش داده می‌شود.

در اینجا مثالی از خروجی آورده شده است:

5.6. فرم – یک مثال کامل

در بخش 2.5.2.1، ما فرم زیر را بررسی کردیم: HTML:

1
 

اکنون یک اکشن [Action08Get] را بررسی می‌کنیم که این فرم (GET) را نمایش می‌دهد، و یک اکشن [Action08Post] که مقادیر وارد شده توسط کاربر (POST) را پردازش می‌کند. یک الگوی کلاسیک.

قالب نما [1] که در بالا نشان داده شده، نمونه‌ای از کلاس [ViewModel08] خواهد بود. این کلاس هر دو نقش را ایفا خواهد کرد:

  • مدل نمایی که توسط یک GET برای اقدام [Action08Get] تولید شده است؛
  • مدل برای اکشن [Action08Post] برای یک درخواست POST.

5.6.1. قالب دامنه [Application]

ما فرض می‌کنیم که عناصری که توسط دکمه‌های رادیویی، چک‌باکس‌ها و لیست‌های مختلف نمایش داده می‌شوند، داده‌های دامنه [Application] هستند. این یک سناریوی رایج است. این اطلاعات از یک فایل پیکربندی یا پایگاه داده‌ای که هنگام راه‌اندازی برنامه از طریق متد [Application_Start] از کلاس [Global.asax] به آن دسترسی پیدا می‌شود، تأمین می‌گردد. این متد به شرح زیر پیاده‌سازی شده است:


    protected void Application_Start()
    {
....

      // بسته‌بندهای مدل
      ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
      ModelBinders.Binders.Add(typeof(ApplicationModel), new ApplicationModelBinder());

      // داده‌های دامنه [Application]
      Application["data"] = new ApplicationModel();
}
  • خط ۷: نوع [ApplicationModel]، که به زودی آن را توصیف خواهیم کرد، با داده‌بند [ApplicationModelBinder]، که قبلاً در صفحه ۸۲ ارائه شده است، مرتبط می‌شود؛
  • خط ۱۰: یک نمونه از نوع [ApplicationModel] در فرهنگ لغت برنامه ثبت می‌شود که با کلید [data] مرتبط است.

کلاس [ApplicationModel] برای محصورسازی تمام داده‌ها در محدوده [Application] استفاده می‌شود. در اینجا، این کلاس داده‌های قابل نمایش توسط فرم را محصور خواهد کرد:


namespace Exemple_03.Models
{
  public class ApplicationModel
  {
    // مجموعه‌ها برای نمایش در فرم
    public Item[] RadioButtonFieldItems { get; set; }
    public Item[] CheckBoxesFieldItems { get; set; }
    public Item[] DropDownListFieldItems { get; set; }
    public Item[] SimpleChoiceListFieldItems { get; set; }
    public Item[] MultipleChoiceListFieldItems { get; set; }

    // ابتدایی‌سازی فیلدها و مجموعه‌ها
    public ApplicationModel()
    {
      RadioButtonFieldItems = new Item[]{
        new Item {Value="1",Label="oui"},
        new Item {Value="2", Label="non"}
      };
      CheckBoxesFieldItems = new Item[]{
        new Item {Value="1",Label="1"},
        new Item {Value="2", Label="2"},
        new Item {Value="3", Label="3"}
      };
      DropDownListFieldItems = new Item[]{
        new Item {Value="1",Label="choix1"},
        new Item {Value="2", Label="choix2"},
        new Item {Value="3", Label="choix3"}
      };
      SimpleChoiceListFieldItems = new Item[]{
        new Item {Value="1",Label="liste1"},
        new Item {Value="2", Label="liste2"},
        new Item {Value="3", Label="liste3"},
        new Item {Value="4", Label="liste4"},
        new Item {Value="5", Label="liste5"}
      };
      MultipleChoiceListFieldItems = new Item[]{
        new Item {Value="1",Label="liste1"},
        new Item {Value="2", Label="liste2"},
        new Item {Value="3", Label="liste3"},
        new Item {Value="4", Label="liste4"},
        new Item {Value="5", Label="liste5"}
      };
    }
    // موارد مجموعه
    public class Item
    {
      public string Label { get; set; }
      public string Value { get; set; }
    }

  }
}
  • خطوط ۴۵–۴۹: عناصر مجموعه‌های مختلف فرم. [Label] متنی است که توسط عنصر فرم نمایش داده می‌شود، و [Value] مقداری است که هنگام انتخاب این عنصر ارسال می‌شود؛
  • خط ۶: مجموعه‌ای که توسط دکمهٔ رادیویی نمایش داده می‌شود؛
  • خط ۷: مجموعه‌ای که توسط کادرهای تیک نمایش داده می‌شود؛
  • خط ۸: مجموعه‌ای که توسط لیست کشویی نمایش داده می‌شود؛
  • خط ۹: مجموعه‌ای که توسط لیست تک‌انتخابی نمایش داده می‌شود؛
  • خط ۱۰: مجموعه‌ای که توسط لیست چندگزینه‌ای نمایش داده می‌شود؛
  • خطوط ۱۳–۴۳: این مجموعه‌ها توسط سازنده بدون پارامتر کلاس مقداردهی اولیه می‌شوند.

مجموعه‌های مختلف فرم زیر را پر خواهند کرد:

5.6.2. قالب اقدام [Action08Get]

فرم قبلی توسط اقدام زیر نمایش داده خواهد شد [Action08Get]:


    // Action08-GET
    [HttpGet]
    public ViewResult Action08Get(ApplicationModel application)
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      return View("Formulaire", new ViewModel08(application));
}
  • خط ۲: [Action08Get] تنها به فرمان [GET] پاسخ خواهد داد؛
  • خط ۳: این قالب، الگوی برنامه‌ای را که همین‌اکنون توصیف کردیم، به‌عنوان پارامتر دریافت می‌کند؛
  • خط ۵: داده‌ها را در کانتینر پویا [ViewBag] اولیه می‌کند؛
  • خط ۶: نمای [/First/Formulaire.cshtml] را با استفاده از مدل [ViewModel08] نمایش می‌دهد. این مدل همان فرم ارائه‌شده در قبل خواهد بود. برای این کار، مدل برنامه—که عناصر قابل نمایش را تعریف می‌کند—را به سازنده پاس می‌کنیم.

5.6.3. مدل برای نما [Formulaire]

کلاس [ViewModel08] مدل فرم خواهد بود. این کلاس به شرح زیر است:


using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Exemple_03.Models;

namespace Exemple_03.Models
{
  public class ViewModel08
  {
    // میدان‌های ورودی
    public string RadioButtonField { get; set; }
    public string[] CheckBoxesField { get; set; }
    public string TextField { get; set; }
    public string PasswordField { get; set; }
    public string TextAreaField { get; set; }
    public string DropDownListField { get; set; }
    public string SimpleChoiceListField { get; set; }
    public string[] MultipleChoiceListField { get; set; }

    //مجموعه‌هایی که باید در فرم نمایش داده شوند
    public ApplicationModel.Item[] RadioButtonFieldItems { get; set; }
    public ApplicationModel.Item[] CheckBoxesFieldItems { get; set; }
    public ApplicationModel.Item[] DropDownListFieldItems { get; set; }
    public ApplicationModel.Item[] SimpleChoiceListFieldItems { get; set; }
    public ApplicationModel.Item[] MultipleChoiceListFieldItems { get; set; }

    // سازنده‌ها
    public ViewModel08()
    {
    }

    public ViewModel08(ApplicationModel application)
    {
      // ابتدای‌سازی مجموعه
      RadioButtonFieldItems = application.RadioButtonFieldItems;
      CheckBoxesFieldItems = application.CheckBoxesFieldItems;
      DropDownListFieldItems = application.DropDownListFieldItems;
      SimpleChoiceListFieldItems = application.SimpleChoiceListFieldItems;
      MultipleChoiceListFieldItems = application.MultipleChoiceListFieldItems;
      // ابتدای فیلد
      RadioButtonField = "2";
      CheckBoxesField = new string[] { "2" };
      TextField = "quelques mots";
      PasswordField = "secret";
      TextAreaField = "ligne1\nligne2";
      DropDownListField = "2";
      SimpleChoiceListField = "3";
      MultipleChoiceListField = new string[] { "1", "3" };
    }
  }
}
  • در یک فرم، دو نوع عنصر وجود دارد: عناصری که نمایش داده می‌شوند و عناصری که برای ورود داده استفاده می‌شوند؛
  • خطوط ۲۰–۲۴ عناصر قابل نمایش را تعریف می‌کنند. این‌ها مجموعه‌های مختلف در فرم هستند. این‌ها در قالب برنامه (خطوط ۳۴–۳۸) یافت می‌شوند؛
  • خطوط ۱۰–۱۷: فیلدهای ورودی فرم را تعریف می‌کنند؛
  • خط ۱۰: [RadioButtonField] مقدار ارسال‌شده را از طریق خطوط زیرِ فرم بازیابی خواهد کرد:

        <!-- دکمه‌های رادیویی -->
        <tr>
          <td>Etes-vous marié(e)</td>
          <td>
<input type="radio" name="RadioButtonField" value="1" />oui              
<input type="radio" name="RadioButtonField" value="2" checked=&quot;checked&quot;/>non              
          </td>
</tr>

توجه کنید که در خطوط ۵ و ۶، ویژگی [name] برای هر دو دکمه رادیویی، نام خاصیتی است که مقداردهی اولیه خواهد شد. در داده‌های ارسال‌شده، یک رشته با شکل زیر یافت می‌شود:


param1=val1&RadioButtonField=2&param2=val2

اگر کاربر گزینه‌ای را که برچسب [non] دارد تیک زده باشد. در واقع، ویژگی [value] همان گزینه‌ای که تیک خورده است ارسال می‌شود.

  • خط ۱۱: [CheckBoxesField] مقادیر ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!-- تیک‌باکس‌ها -->
        <tr>
          <td>Cases à cocher</td>
          <td>
<input type="checkbox" name="CheckBoxesField" value="1" />1              
<input type="checkbox" name="CheckBoxesField" value="2" checked=&quot;checked&quot;/>2              
<input type="checkbox" name="CheckBoxesField" value="3" />3              
</td>

توجه کنید که در خطوط ۵ و ۶، ویژگی [name] مربوط به چک‌باکس‌ها، نام خصوصیتی است که مقداردهی اولیه خواهد شد. در داده‌های ارسال‌شده، یک رشته به شکل زیر است:


param1=val1&CheckBoxesField=2&CheckBoxesField=3&param2=val2

اگر کاربر کادرهای تیک‌دار با برچسب‌های [2] و [3] را تیک زده باشد. این ویژگی [value] گزینه‌های تیک‌خورده است که ارسال می‌شود. این به این دلیل است که ممکن است چندین پارامتر با نام یکسان ارسال شوند، به همین دلیل [CheckBoxesField] به جای یک مقدار واحد، یک آرایه از مقادیر است. اگر هیچ کادری تیک‌خورده نباشد، پارامتر [CheckBoxesField] در رشته ارسال‌شده وجود نخواهد داشت و ویژگی با همین نام در مدل مقداردهی اولیه نخواهد شد. این می‌تواند مشکل‌ساز باشد، همان‌طور که خواهیم دید.

  • خط ۱۲: [TextField] مقدار ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

          <!-- میدان ورودی متن تک‌خطی -->
          <tr>
            <td>Champ de saisie</td>
            <td>
              <input type="text" name="TextField" value="quelques mots" size="30" />
            </td>
</tr>

خط ۵: ویژگی [name] فیلد ورودی، نام خصوصیتی است که مقداردهی خواهد شد. در داده‌های ارسال‌شده، یک رشته به شکل زیر وجود خواهد داشت:


param1=val1&TextField=abcdef&param2=val2

اگر کاربر [abcdef] را در فیلد ورودی وارد کرده باشد.

  • خط ۱۳: [PasswordField] مقدار ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!-- میدان وارد کردن رمز عبور -->
        <tr>
          <td>Mot de passe</td>
          <td>
            <input type="password" name="PasswordField" value="secret" size="30" />
          </td>
</tr>

خط ۵: ویژگی [name] فیلد ورودی نام خاصیتی است که باید مقداردهی اولیه شود. در داده‌های ارسال‌شده، یک رشته به شکل زیر وجود خواهد داشت:


param1=val1&PasswordField=abcdef&param2=val2

اگر کاربر [abcdef] را در فیلد ورودی وارد کرده باشد.

  • خط 14: [TextAreaField] مقدار ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!-- میدان ورودی متن چندخطی -->
        <tr>
          <td>Boîte de saisie</td>
          <td>
            <textarea name="TextAreaField" cols="40" rows="3">ligne1
ligne2</textarea>
          </td>
</tr>

خط ۵: ویژگی [name] فیلد ورودی، نام خصوصیتی است که باید مقداردهی اولیه شود. در داده‌های ارسال‌شده، یک رشته به شکل زیر وجود خواهد داشت:


param1=val1&TextAreaField=abcdef%0D%OAhijk&param2=val2

اگر کاربر در فیلد ورودی، [abcdef] را وارد کرده و پس از آن یک خط جدید و سپس [ijk] را وارد کرده باشد.

  • خط ۱۵: [DropDownListField] مقدار ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!-- لیست کشویی -->
        <tr>
          <td>Liste déroulante</td>
          <td>
            <select name="DropDownListField">
<option value="1" >choix1</option>
<option value="2" selected=&quot;selected&quot;>choix2</option>
<option value="3" >choix3</option>
            </select>
</tr>

خط ۵: ویژگی [name] تگ <select> نام خاصیتی است که باید مقداردهی اولیه شود. در داده‌های ارسال‌شده، یک رشته به شکل زیر وجود خواهد داشت:


param1=val1&DropDownListField=1&param2=val2

اگر کاربر گزینه [choix1] را انتخاب کرده باشد. این ویژگی [value] از گزینه انتخاب‌شده است که ارسال می‌شود.

  • خط ۱۶: [SingleChoiceListField] مقدار ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!-- لیست انتخاب تک‌گانه -->
        <tr>
          <td>Liste à choix unique</td>
          <td>
            <select name="SimpleChoiceListField" size="3">
<option value="1" >liste1</option>
<option value="2" >liste2</option>
<option value="3" selected=&quot;selected&quot;>liste3</option>
<option value="4" >liste4</option>
<option value="5" >liste5</option>

            </select>
</tr>

خط ۵: ویژگی [name] تگ <select> نام خاصیتی است که مقداردهی اولیه خواهد شد. این ویژگی [size="3"] است که تضمین می‌کند هیچ فهرست کشویی وجود ندارد. در داده‌های ارسال‌شده، رشته‌ای به شکل زیر خواهید یافت:


param1=val1&SimpleChoiceListField=3&param2=val2

اگر کاربر گزینه [liste3] را انتخاب کرده باشد. این ویژگی [value]ِ گزینه انتخاب‌شده است که ارسال می‌شود. پارامتر [SingleChoiceListField] ممکن است در رشته ارسالی وجود نداشته باشد اگر هیچ موردی انتخاب نشده باشد.

  • خط ۱۷: [MultipleChoiceListField] مقادیر ارسال‌شده توسط خطوط زیر فرم را بازیابی خواهد کرد:

        <!--فهرست چندگزینه‌ای -->
        <tr>
          <td>Liste à choix multiple</td>
          <td>
            <select name="MultipleChoiceListField" size="3" multiple="multiple">
<option value="1" selected=&quot;selected&quot;>liste1</option>
<option value="2" >liste2</option>
<option value="3" selected=&quot;selected&quot;>liste3</option>
<option value="4" >liste4</option>
<option value="5" >liste5</option>
            </select>
</tr>

خط ۵: ویژگی [name] تگ <select> نام خاصیتی است که باید مقداردهی اولیه شود. این ویژگی [size="3"] است که تضمین می‌کند هیچ فهرست کشویی وجود نداشته باشد، و ویژگی [multiple] است که به کاربر اجازه می‌دهد با نگه داشتن کلید [Ctrl] چندین مورد را انتخاب کند. در داده‌های ارسال‌شده، رشته‌ای به شکل زیر خواهید یافت:


param1=val1&MultipleChoiceListField=1&MultipleChoiceListField=3&param2=val2

اگر کاربر گزینه‌های [liste1] و [liste3] را انتخاب کرده باشد. این ویژگی [value] گزینه‌های انتخاب‌شده است که ارسال می‌شود. به این دلیل که چندین پارامتر با نام یکسان می‌توانند ارسال شوند، [MultipleChoiceListField] به جای یک مقدار واحد، یک آرایه از مقادیر است. اگر هیچ کادری تیک‌خورده نباشد، پارامتر [MultipleChoiceListField] در رشته ارسال‌شده وجود نخواهد داشت و ویژگی با همین نام در مدل مقداردهی اولیه نخواهد شد.

میدان‌های ورودی مختلف نشان‌داده‌شده در بالا، مقادیر ارسال‌شده توسط فرم را دریافت خواهند کرد. آن‌ها همچنین می‌توانند قبل از ارسال فرم مقداردهی اولیه شوند. این کاری است که در اینجا انجام شده است:


      // ابتدای فیلد
      RadioButtonField = "2";
      CheckBoxesField = new string[] { "2" };
      TextField = "quelques mots";
      PasswordField = "secret";
      TextAreaField = "ligne1\nligne2";
      DropDownListField = "2";
      SimpleChoiceListField = "3";
MultipleChoiceListField = new string[] { "1", "3" };

اگر این مقادیر پس از ارسال فرم با استفاده از POST به دست آمده بودند، این بدان معنا بود که کاربر:

  • خط ۲: دکمه رادیویی [non] را انتخاب کرده است؛
  • خط ۳: گزینه [2] را در کادرهای تیک‌خورده علامت‌زده است؛
  • خط ۴: مقدار [quelques mots] را در فیلد ورودی وارد کرده است؛
  • خط ۵: رمز عبور [secret] را وارد کرده است؛
  • خط ۶: [ligne1\nligne2] را در کادر ورودی چندخطی تایپ کنید؛
  • خط ۷: گزینه [choix2] را از فهرست کشویی انتخاب کنید؛
  • خط ۸: گزینه [liste3] را از لیست تک‌انتخابی انتخاب کرد؛
  • خط ۹: گزینه‌های [liste1] و [liste3] را از لیست چندگزینه‌ای انتخاب کرد؛

ما فرض می‌کنیم که یک POST رخ داده است و می‌خواهیم فرم را دقیقاً همان‌طور که وارد شده بازگردانیم. این همان کاری است که برای مثال، هنگامی که یک فرم نادرست به کاربر بازگردانده می‌شود، اتفاق می‌افتد. فرم دقیقاً همان‌طور که وارد شده بازگردانده می‌شود.

5.6.4. نما [Formulaire]

نما [/First/Formulaire.cshtml] فرم را نمایش می‌دهد:


@model Exemple_03.Models.ViewModel08
@using Exemple_03.Models
@{
  Layout = null;
}
<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Formulaire</title>
</head>
<body>
  <form method="post" action="Action08Post">
    <h2>Formulaire ASP.NET MVC</h2>
    <h3>Affiché par : @ViewBag.info</h3>
    <table>
      <thead></thead>
      <tbody>
        <!-- دکمه‌های رادیویی -->
        <tr>
          <td>Etes-vous marié(e)</td>
          <td>
            @foreach (ApplicationModel.Item item in @Model.RadioButtonFieldItems)
            {
              string strChecked = item.Value == @Model.RadioButtonField ? "checked=\"checked\"" : "";
              <input type="radio" name="RadioButtonField" value="@item.Value" @strChecked/>@item.Label
              <text/>
            }
          </td>
        </tr>
...
      </tbody>
    </table>
    <input type="submit" value="Valider" />
  </form>
</body>
</html>
  • خط ۱: [ViewModel08] قالب فرم است؛
  • خط ۱۲: تگ <form> برای فرم. این با استفاده از روش [POST] (ویژگی method) به URL [/First/Action08Post] ارسال خواهد شد. (ویژگی action);
  • خط ۳۳: دکمه از نوع [submit]، که برای ارسال فرم استفاده می‌شود؛
  • خطوط ۲۲–۲۷: نمایش دکمه‌های رادیویی:
  
  • خط ۲۲: مجموعه نمایش داده شده توسط دکمه رادیویی پردازش می‌شود؛
  • خط ۲۴: دکمه‌ای که ویژگی [value] آن مقدار ویژگی [RadioButtonField] را در خود دارد باید انتخاب شود. برای این کار، باید ویژگی [checked="checked"] را داشته باشد؛
  • خط ۲۵: ایجاد تگ <input type="radio"> با مقدار [@item.Value] و برچسب [@item.Label];
  • خط ۲۶: تگ <text/> یک تگ شناخته‌شده HTML نیست. این تگ برای [Razor] قرار دارد. هنگام برخورد با آن، [Razor] یک خط‌شکن ایجاد خواهد کرد. این امر هیچ تأثیری بر فرم نمایش داده شده ندارد اما بر کد تولید شده HTML تأثیر می‌گذارد. برچسب‌های <input type="radio"> در این صورت به جای قرار گرفتن در یک خط، در دو خط مختلف قرار می‌گیرند. این کار باعث می‌شود هنگام مشاهده کد منبع صفحه نمایش داده شده در مرورگر، کد خواناتر شود؛

بیایید سایر عناصر نما را بررسی کنیم:


        <!-- تیک‌باکس‌ها -->
        <tr>
          <td>Cases à cocher</td>
          <td>
            @{
              foreach (ApplicationModel.Item item in @Model.CheckBoxesFieldItems)
              {
                string strChecked = @Model.CheckBoxesField.Contains(item.Value) ? "checked=\"checked\"" : "";
              <input type="checkbox" name="CheckBoxesField" value="@item.Value" @strChecked/>@item.Label
              <text/>
              }
            }
</td>
  • خط ۶: ما روی مجموعه نمایش‌داده‌شده توسط چک‌باکس‌ها حلقه می‌زنیم؛
  • خط ۸: کادری که ویژگی [value] آن روی یکی از مقادیر خاصیت [CheckBoxesField] تنظیم شده باشد، باید تیک خورده باشد. برای این کار، باید ویژگی [checked="checked"] را داشته باشد. ما از عبارت LINQ برای بررسی اینکه آیا یک مقدار در یک آرایه وجود دارد یا خیر استفاده می‌کنیم؛
  • خط ۲۵: تولید تگ <input type="checkbox"> با مقدار [@item.Value] و برچسب [@item.Label

<!-- میدان ورودی متن تک‌خطی -->
          <tr>
            <td>Champ de saisie</td>
            <td>
              <input type="text" name="TextField" value="@Model.TextField" size="30" />
            </td>
          </tr>
        <!-- میدان وارد کردن رمز عبور -->
        <tr>
          <td>Mot de passe</td>
          <td>
            <input type="password" name="PasswordField" value="@Model.PasswordField" size="30" />
          </td>
        </tr>
        <!-- میدان ورودی متن چندخطی -->
        <tr>
          <td>Boîte de saisie</td>
          <td>
            <textarea name="TextAreaField" cols="40" rows="3">@Model.TextAreaField</textarea>
          </td>
        </tr>
  • خطوط ۵ و ۱۲: ویژگی [value] تگ روی مقدار موجود در قالب تنظیم می‌شود؛
  • خط ۱۹: همین، اما با نحو متفاوت.

        <!-- لیست کشویی -->
        <tr>
          <td>Liste déroulante</td>
          <td>
            <select name="DropDownListField">
              @{
                foreach (ApplicationModel.Item item in @Model.DropDownListFieldItems)
                {
                  string strChecked = item.Value == @Model.DropDownListField ? "selected=\"selected\"" : "";
                <option value="@item.Value" @strChecked>@item.Label</option>
                }
              }
            </select>
</tr>
  • خط ۷: مجموعه نمایش داده شده توسط لیست کشویی پیمایش می‌شود؛
  • خط ۹: یک گزینه که ویژگی [value] آن دارای مقدار خاصیت [DropDownListField] است باید سپس انتخاب شود. برای این کار، باید ویژگی [selected="selected"] را داشته باشد؛
  • خط 25: تولید تگ <option value="valeur">libellé</option> با مقدار [@item.Value] و برچسب [@item.Label];

        <!-- لیست انتخاب تک -->
        <tr>
          <td>Liste à choix unique</td>
          <td>
            <select name="SimpleChoiceListField" size="3">
              @{
                foreach (ApplicationModel.Item item in @Model.SimpleChoiceListFieldItems)
                {
                  string strChecked = item.Value == @Model.SimpleChoiceListField ? "selected=\"selected\"" : "";
                <option value="@item.Value" @strChecked>@item.Label</option>
                }
              }
            </select>
</tr>

توضیحات همانند لیست کشویی است.


        <!-- فهرست چندگزینه‌ای -->
        <tr>
          <td>Liste à choix multiple</td>
          <td>
            <select name="MultipleChoiceListField" size="3" multiple="multiple">
              @{
                foreach (ApplicationModel.Item item in @Model.MultipleChoiceListFieldItems)
                {
                  string strChecked = @Model.MultipleChoiceListField.Contains(item.Value) ? "selected=\"selected\"" : "";
                <option value="@item.Value" @strChecked>@item.Label</option>
                }
              }
            </select>
</tr>
  • خط ۷: ما بر روی مجموعه نمایش‌داده‌شده توسط لیست تکرار می‌کنیم؛
  • خط ۹: یک گزینه که ویژگی [value] آن یکی از مقادیر خاصیت [MultipleChoiceListField] را داشته باشد، باید انتخاب شود. برای این کار، باید ویژگی [selected="selected"] را داشته باشد. ما از یک عبارت LINQ برای بررسی اینکه آیا یک مقدار در یک آرایه وجود دارد یا خیر استفاده می‌کنیم؛
  • خط ۱۰: تولید تگ libellé/option با مقدار [@item.Value] و برچسب [@item.Label];

5.6.5. پردازش POST از فرم

ما مشاهده کردیم که فرم باید به اقدام [Action08Post] ارسال می‌شد:


  <form method="post" action="Action08Post">

عمل [Action08Post] به شرح زیر است:


    // اقدام08-POST
    [HttpPost]
    public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      ViewModel08 modèle = new ViewModel08(application);
      TryUpdateModel(modèle,posted);
      return View("Formulaire", modèle);
}
  • خط ۳: قالب برنامه به همراه مقادیر ارسال‌شده به‌عنوان یک پارامتر ارسال می‌شود. این مقادیر در نوع با نام [FormCollection] در دسترس هستند. مقدار پارامتر ارسال‌شده [RadioButtonField] از طریق عبارت posted[" RadioButtonField"] به دست می‌آید. این مقدار یک رشته یا نشانگر null را برمی‌گرداند. اگر `posted[" CheckBoxesField"]` را بنویسید، یک آرایه از رشته‌ها یا نشانگر null دریافت خواهید کرد؛
  • پس چرا ننویسیم:

public ViewResult Action08Post(ApplicationModel application, ViewModel08 posted)

دو دلیل وجود دارد:

  • دلیل اول این است که فریم‌ورک مدل [ViewModel08] را با استفاده از سازنده بدون پارامتر نمونه سازی می‌کند، که به این معنی است که مجموعه‌های مدل مقداردهی اولیه نخواهند شد؛
  • دلیل دوم این است که می‌خواهیم کنترل کنیم چه چیزی وارد مدل می‌شود. ما می‌دانیم که چهار منبع ممکن برای مدل وجود دارد: پارامترهای یک GET، یک POST، مسیر استفاده شده، و موارد یک فایل uploadé. در اینجا، می‌خواهیم مدل را صرفاً با مقادیر ارسال‌شده مقداردهی اولیه کنیم.
  • خط ۶: ما مدل را با استفاده از سازنده صحیح نمونه سازی می‌کنیم؛
  • خط ۷: آن را با مقادیر ارسال‌شده مقداردهی اولیه می‌کنیم. پس از این عملیات، مدل با داده‌های وارد شده توسط کاربر مطابقت دارد؛
  • خط ۸: فرم را دوباره نمایش می‌دهیم. کاربر آن را دقیقاً همان‌طور که وارد کرده است خواهد دید.

بیایید به یک مثال نگاه کنیم:

در [2]، نتیجه [POST] دقیقاً آنچه را که در [1] وارد شده منعکس می‌کند.

5.6.6. پردازش ناهنجاری‌ها در POST

ما بیان کرده‌ایم که اگر هیچ ارزشی برای فیلدهای [CheckBoxesField, SimpleChoiceListField, MultipleChoiceListField] تیک‌خورده یا انتخاب نشده باشد، پارامترهای متناظر در رشته ارسال‌شده گنجانده نمی‌شوند و در نتیجه، ویژگی‌های با همان نام‌ها در قالب اولیه نشده‌اند.

بیایید به مثال زیر نگاه کنیم:

  • در [1]، هیچ چک‌باکسی تیک‌خورده نیست؛
  • در [2]، [POST] یک کادر تیک‌خورده را برمی‌گرداند.

توضیحات به شرح زیر است:

  • از آنجایی که هیچ کادر تیک‌خورده‌ای انتخاب نشده است، پارامتر [CheckBoxesField] در مقادیر ارسال‌شده گنجانده نمی‌شود؛
  • عمل [Action08Post] به شرح زیر انجام می‌شود:

    [HttpPost]
    public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
    {
      ViewBag.info = ...
      ViewModel08 modèle = new ViewModel08(application);
      TryUpdateModel(modèle,posted);
      return View("Formulaire", modèle);
}
  • خط ۵: قالب فرم نمونه‌سازی می‌شود. با این حال، سازنده‌ی مورد استفاده آرایه ["2"] را به ویژگی [CheckBoxesField] اختصاص می‌دهد؛
  • خط ۶: مقادیر ارسال‌شده در قالب ذخیره می‌شوند. از آنجایی که پارامتر [CheckBoxesField] در میان مقادیر ارسال‌شده نیست، مقداردهی به خصوصیتی با همین نام انجام نمی‌شود. بنابراین، مقدار ["2"] خود را حفظ می‌کند، که به این معنی است که هنگام نمایش، تیک گزینه شماره ۲ در حالی که نباید، زده می‌شود.

این مشکل را می‌توان به روش‌های مختلفی حل کرد. ما انتخاب کرده‌ایم که آن را در کد مربوط به اقدام [Action08Post] حل کنیم:


// Action08-POST
    [HttpPost]
    public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      ViewModel08 modèle = new ViewModel08(application);
      TryUpdateModel(modèle,posted);
      //پردازش مقادیر ارسال‌نشده
      if (posted["CheckBoxesField"] == null)
      {
        modèle.CheckBoxesField = new string[] { };
      }
      if (posted["SimpleChoiceListField"] == null)
      {
        modèle.SimpleChoiceListField = "";
      }
      if (posted["MultipleChoiceListField"] == null)
      {
        modèle.MultipleChoiceListField = new string[] { };
      }
      //نمایش فرم
      return View("Formulaire", modèle);
    }
  • خطوط ۹–۲۰: ما بررسی می‌کنیم که آیا پارامترهای خاصی ارسال شده‌اند یا خیر. اگر ارسال نشده باشند، آن‌ها را با مقداری که نشان‌دهنده عدم ورود چیزی توسط کاربر است، مقداردهی اولیه می‌کنیم. این بررسی برای لیست کشویی انجام نشده است، که برخلاف سایر لیست‌ها، همیشه یک مورد در آن انتخاب شده است.

از خوانندگان دعوت می‌شود تا این نسخه جدید را آزمایش کنند.

5.7. استفاده از روش‌های تخصصی برای تولید فرم

5.7.1. فرم جدید

ما در حال ایجاد یک فرم جدید به نام [Formulaire2.cshtml] هستیم که فرم مشابهی با فرم قبلی تولید خواهد کرد:

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


        <!-- لیست کشویی -->
        <tr>
          <td>Liste déroulante</td>
          <td>
            <select name="DropDownListField">
              @{
                foreach (ApplicationModel.Item item in @Model.DropDownListFieldItems)
                {
                  string strChecked = item.Value == @Model.DropDownListField ? "selected=\"selected\"" : "";
                <option value="@item.Value" @strChecked>@item.Label</option>
                }
              }
            </select>
</tr>

این کد دو عیب دارد:

  • مهم‌ترین آن این است که ماهیت کامپوننت – در این مورد، یک لیست کشویی – به دلیل پیچیدگی کد از بین می‌رود؛
  • خط ۵: اگر در نام ویژگی مدل که باید به‌عنوان صفت [name] استفاده شود اشتباهی مرتکب شوید، تنها در زمان اجرا متوجه آن خواهید شد.

کلاس‌های ASP.NET و MVC متدهای تخصصی‌ای به نام [HTML Helpers] ارائه می‌دهند که همان‌طور که از نامشان پیداست، برای تسهیل تولید HTML، به‌ویژه برای فرم‌ها، طراحی شده‌اند. با استفاده از این کلاس‌ها، لیست کشویی قبلی به صورت زیر نوشته می‌شود:


        <!-- لیست کشویی -->
        <tr>
          <td>Liste déroulante</td>
          <td>@Html.DropDownListFor(m => m.DropDownListField,
           new SelectList(@Model.DropDownListFieldItems, "Value", "Label"))
          </td>
</tr>

لیست کشویی توسط خطوط ۴–۵ تولید می‌شود. کد به‌طور قابل توجهی ساده‌تر است. کد HTML تولیدشده برای لیست کشویی به شرح زیر است:


        <!-- لیست کشویی -->
        <tr>
          <td>Liste déroulante</td>
          <td><select id="DropDownListField" name="DropDownListField"><option value="1">choix1</option>
<option selected="selected" value="2">choix2</option>
<option value="3">choix3</option>
</select></td>
</tr>
  • خط ۴: ویژگی [name] صحیح است؛
  • خطوط ۴–۶: گزینه‌ها به‌درستی تولید شده‌اند و گزینهٔ صحیح انتخاب شده است.

بیایید به کدی که این خطوط را تولید کرده است بازگردیم HTML:


@Html.DropDownListFor(m => m.DropDownListField, new SelectList(@Model.DropDownListFieldItems, "Value", "Label"))
  • پارامتر اول یک تابع lambda (که نام آن است) است که در آن m نمایانگر مدل نما (view model) است و m.DropDowListField یک ویژگی از آن مدل است. کدساز HTML از نام این ویژگی برای تولید ویژگی‌های [id] و [name] برای [select] که قرار است تولید شود، استفاده خواهد کرد. اگر از یک ویژگی وجود نداشته استفاده شود، خطا در زمان کامپایل رخ می‌دهد نه در زمان اجرا. این یک بهبود نسبت به راه‌حل قبلی است که در آن خطاهای نام‌گذاری تنها در زمان اجرا تشخیص داده می‌شدند؛
  • پارامتر دوم برای مشخص کردن مجموعه عناصری استفاده می‌شود که لیست کشویی را پر خواهند کرد. کلاس [SelectList] برای ساخت این مجموعه استفاده می‌شود:
    • پارامتر اول آن هر مجموعه‌ای از عناصر است. در اینجا، ما یک مجموعه از نوع [Item] داریم؛
    • پارامتر دوم آن، خصوصیت عناصری است که مقدار را برای تگ <option> فراهم می‌کنند. در اینجا، این خصوصیت [Value] از کلاس [Item] است؛
    • پارامتر سوم آن، ویژگیِ عناصری است که برچسبِ تگ <option> را فراهم می‌کند. در اینجا، این ویژگی [Label] از کلاس [Item] است؛
  • برای تعیین اینکه کدام گزینه باید انتخاب شود (ویژگی selected)، چارچوب همان کاری را انجام می‌دهد که ما انجام می‌دهیم: مقدار گزینه را با مقدار فعلی ویژگی [DropDownListField] مقایسه می‌کند.

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

دکمه‌های رادیویی

کد جدید به شرح زیر است:


        <!-- دکمه‌های رادیویی -->
        <tr>
          <td>Etes-vous marié(e)</td>
          <td>
            @{
    foreach (ApplicationModel.Item item in @Model.RadioButtonFieldItems)
    {
              @Html.RadioButtonFor(m => m.RadioButtonField, @item.Value)@item.Label
              <text/>
    }
            }
          </td>
</tr>

کد تولید شده HTML به شرح زیر است:


        <!-- دکمه‌های رادیویی -->
        <tr>
          <td>Etes-vous marié(e)</td>
          <td>
<input id="RadioButtonField" name="RadioButtonField" type="radio" value="1" />oui              
<input checked="checked" id="RadioButtonField" name="RadioButtonField" type="radio" value="2" />non              
          </td>
</tr>

روش مورد استفاده [Html.RadioButtonFor] است:

@Html.RadioButtonFor(m => m.RadioButtonField, @item.Value)
  • پارامتر اول، ویژگی مدل است که با دکمه رادیویی مرتبط خواهد شد (ویژگی [name])؛
  • پارامتر دوم مقداری است که باید به دکمه رادیویی اختصاص داده شود (ویژگی [value]).

تیک‌باکس‌ها

کد به شرح زیر تغییر می‌کند:


        <!-- تیک‌باکس‌ها -->
        <tr>
          <td>Cases à cocher</td>
          <td>
            @{
              @Html.CheckBoxFor(m=>m.CheckBoxField1) @Model.CheckBoxesFieldItems[0].Label
              @Html.CheckBoxFor(m=>m.CheckBoxField2) @Model.CheckBoxesFieldItems[1].Label
              @Html.CheckBoxFor(m=>m.CheckBoxField3) @Model.CheckBoxesFieldItems[2].Label
            }
</td>

روش مورد استفاده برای تولید چک‌باکس‌ها [Html.CheckBoxFor] است:

Html.CheckBoxFor(m=>m.Propriété)

پارامتر، ویژگی بولین مدلی است که با چک‌باکس مرتبط خواهد شد. اگر [Propriété=true] باشد، چک‌باکس تیک‌خورده خواهد بود. اگر [Propriété=false] باشد، چک‌باکس تیک‌خورده نخواهد بود. در همه موارد، ویژگی [value] روی true تنظیم می‌شود. کد تولیدشده HTML به شرح زیر است:


<input id="Propriété" name="Propriété" type="checkbox" value="true" />
<input name="Propriété" type="hidden" value="false" />
  • خط ۱: تیک‌باکس با ویژگی [value="true"];
  • خط ۲: یک فیلد مخفی (type=hidden) با همان نام ([Propriété]) که با تیک‌باکس دارای ویژگی [value="false"] یکسان است. چرا دو تگ [input] با نام یکسان وجود دارد؟ دو سناریو وجود دارد:
  • کادر تیک در خط ۱ تیک خورده است. در این حالت، رشته پارامتر ارسال‌شده Property=true&Property=false است (خطوط ۱ و ۲). از آنجا که ویژگی [Propriété] تنها یک مقدار را انتظار دارد، می‌توان فرض کرد که چارچوب مقدار [true] را به [Propriété] اختصاص می‌دهد. برای این کار، کافی است یک عملیات «یا» (OR) منطقی بین مقادیر دریافتی انجام دهد؛
  • کادر در خط ۱ تیک‌خورده نیست. بنابراین، رشته پارامتر ارسال‌شده فقط شامل Property=false است و در نتیجه ویژگی [Propriété] مقدار [false] را دریافت می‌کند که صحیح است (کادر تیک‌خورده نبود).

میدان ورودی تک‌خطی

کد جدید به شرح زیر است:


          <!-- میدان ورودی متن تک‌خطی -->
          <tr>
            <td>Champ de saisie</td>
            <td>
              @Html.TextBoxFor(m => m.TextField, new { size = "30" })
            </td>
</tr>

کد تولید شده HTML به شرح زیر است:


          <!-- میدان ورودی متن تک‌خطی -->
          <tr>
            <td>Champ de saisie</td>
            <td>
              <input id="TextField" name="TextField" size="30" type="text" value="quelques mots" />
            </td>
</tr>

روش مورد استفاده به شرح زیر است:


@Html.TextBoxFor(m => m.TextField, new { size = "30" })
  • پارامتر اول، ویژگی مدل مرتبط با فیلد ورودی را مشخص می‌کند. نام این ویژگی در ویژگی‌های [name] و [id] تگ <input> تولید شده استفاده خواهد شد و مقدار آن به ویژگی [value] اختصاص داده می‌شود؛
  • پارامتر دوم یک کلاس ناشناس است که ویژگی‌های خاصی از تگ تولیدشده HTML را مشخص می‌کند، در این مورد ویژگی [size].

میدان وارد کردن رمز عبور

کد جدید به شرح زیر است:


        <!-- میدان وارد کردن رمز عبور -->
        <tr>
          <td>Mot de passe</td>
          <td>
            @Html.PasswordFor(m => m.PasswordField, new { size = "15" })
          </td>
</tr>

کد تولید شده HTML به شرح زیر است:


        <!-- میدان وارد کردن رمز عبور -->
        <tr>
          <td>Mot de passe</td>
          <td>
            <input id="PasswordField" name="PasswordField" size="15" type="password" />
          </td>
</tr>

روش مورد استفاده به شرح زیر است:


@Html.PasswordFor(m => m.PasswordField, new { size = "15" })

این فرایند مشابه روش [Html.TexBoxFor] است.

میدان ورودی چندخطی

کد جدید به شرح زیر است:


        <!-- میدان ورودی متن چندخطی -->
        <tr>
          <td>Boîte de saisie</td>
          <td>
            @Html.TextAreaFor(m => m.TextAreaField, new { cols = "30", rows = "5" })
          </td>
</tr>

کد تولیدشده HTML به شرح زیر است:


        <!-- میدان ورودی متن چندخطی -->
        <tr>
          <td>Boîte de saisie</td>
          <td>
            <textarea cols="30" id="TextAreaField" name="TextAreaField" rows="5">
ligne1
ligne2</textarea>
          </td>
</tr>

روش مورد استفاده به شرح زیر است:


@Html.TextAreaFor(m => m.TextAreaField, new { cols = "30", rows = "5" })

عملکرد مشابه روش [Html.TexBoxFor] است.

فهرست تک‌انتخابی

کد جدید به شرح زیر است:


        <!-- فهرست انتخاب تک‌گانه -->
        <tr>
          <td>Liste à choix unique</td>
          <td>
          @Html.DropDownListFor(m => m.SimpleChoiceListField, new SelectList(@Model.SimpleChoiceListFieldItems, "Value", "Label"), new { size = "3" })
</tr>

و کد تولید شده توسط HTML به شرح زیر است:


        <!-- فهرست انتخاب تک‌گانه -->
        <tr>
          <td>Liste à choix unique</td>
          <td>
          <select id="SimpleChoiceListField" name="SimpleChoiceListField" size="3">
<option value="1">liste1</option>
<option value="2">liste2</option>
<option selected="selected" value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
</tr>

ما قبلاً روش [Html.DropDownListFor] را بررسی کرده‌ایم. تنها تفاوت در اینجا پارامتر سوم است که برای مشخص کردن یک ویژگی [size] غیر از 1 استفاده می‌شود. این ویژگی است که لیست را از یک لیست کشویی ([size=1]) به یک لیست ساده تبدیل می‌کند.

فهرست چندگزینه‌ای

کد جدید به شرح زیر است:


        <!-- فهرست چندگزینه‌ای -->
        <tr>
          <td>Liste à choix multiple</td>
          <td>
          @Html.ListBoxFor(m => m.MultipleChoiceListField, new SelectList(@Model.MultipleChoiceListFieldItems, "Value", "Label"), new { size = "5" })
</tr>

و کد تولید شده HTML به شرح زیر است:


        <!-- فهرست چندگزینه‌ای -->
        <tr>
          <td>Liste à choix multiple</td>
          <td>
          <select id="MultipleChoiceListField" multiple="multiple" name="MultipleChoiceListField" size="5">
<option selected="selected" value="1">liste1</option>
<option value="2">liste2</option>
<option selected="selected" value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
</tr>

روش


@Html.ListBoxFor(m => m.MultipleChoiceListField, new SelectList(@Model.MultipleChoiceListFieldItems, "Value", "Label"), new { size = "5" })

به همان شیوه‌ای عمل می‌کند که متد [Html.DropDownListFor] عمل می‌کند، با این تفاوت که یک لیست چندگزینه‌ای تولید می‌کند. گزینه‌های انتخاب‌شده آنهایی هستند که مقادیرشان (ویژگی value) در جدول [MultipleChoiceListField] وجود دارد.

تگ <form> نیز می‌تواند با استفاده از یک متد تولید شود:


  @using (Html.BeginForm("Action09Post", "First"))
  {
...
  }

کد تولید شده HTML به شرح زیر است:


<form action="/First/Action09Post" method="post">    
    ...
</form>

روش


Html.BeginForm("Action09Post", "First")

نام یک اکشن را به‌عنوان اولین پارامتر و نام یک کنترلر را به‌عنوان دومین پارامتر می‌گیرد.

5.7.2. اقدامات و مدل

فرم توسط اکشن زیر، [Action09Get]، رندر خواهد شد:


    // Action09-GET
    [HttpGet]
    public ViewResult Action09Get(ApplicationModel application)
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      return View("Formulaire2", new ViewModel09(application));
}

ویوی بازگردانده‌شده در خط ۶، [Formulaire2] است که با مدل زیر مرتبط است: [ViewModel09]:


using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Exemple_03.Models;

namespace Exemple_03.Models
{
  public class ViewModel09
  {
    // fields of input
    public string RadioButtonField { get; set; }
    public bool CheckBoxField1 { get; set; }
    public bool CheckBoxField2 { get; set; }
    public bool CheckBoxField3 { get; set; }
    public string TextField { get; set; }
    public string PasswordField { get; set; }
    public string TextAreaField { get; set; }
    public string DropDownListField { get; set; }
    public string SimpleChoiceListField { get; set; }
    public string[] MultipleChoiceListField { get; set; }

    // مجموعه‌هایی که باید در فرم نمایش داده شوند
    public ApplicationModel.Item[] RadioButtonFieldItems { get; set; }
    public ApplicationModel.Item[] CheckBoxesFieldItems { get; set; }
    public ApplicationModel.Item[] DropDownListFieldItems { get; set; }
    public ApplicationModel.Item[] SimpleChoiceListFieldItems { get; set; }
    public ApplicationModel.Item[] MultipleChoiceListFieldItems { get; set; }

    // سازنده‌ها
    public ViewModel09()
    {
    }

    public ViewModel09(ApplicationModel application)
    {
      // ابتدای‌سازی مجموعه
      RadioButtonFieldItems = application.RadioButtonFieldItems;
      CheckBoxesFieldItems = application.CheckBoxesFieldItems;
      DropDownListFieldItems = application.DropDownListFieldItems;
      SimpleChoiceListFieldItems = application.SimpleChoiceListFieldItems;
      MultipleChoiceListFieldItems = application.MultipleChoiceListFieldItems;
      // ابتدای‌سازی فیلد
      RadioButtonField = "2";
      CheckBoxField2 = true;
      TextField = "quelques mots";
      PasswordField = "secret";
      TextAreaField = "ligne1\nligne2";
      DropDownListField = "2";
      SimpleChoiceListField = "3";
      MultipleChoiceListField = new string[] { "1", "3" };
    }
  }
}

[ViewModel09] در نحوهٔ مدیریت کادرهای تیک با [ViewModel08] متفاوت است. به جای داشتن یک آرایه از سه کادر تیک، از سه کادر تیک مجزا استفاده شده است (خطوط ۱۱–۱۳).

این فرم توسط اقدام زیر، [Action09Post]، پردازش خواهد شد:


    // Action09-POST
    [HttpPost]
    public ViewResult Action09Post(ApplicationModel application, FormCollection posted)
    {
      ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
      ViewModel09 modèle = new ViewModel09(application);
      TryUpdateModel(modèle, posted);
      //پردازش مقادیر ارسال‌نشده
      if (posted["SimpleChoiceListField"] == null)
      {
        modèle.SimpleChoiceListField = "";
      }
      if (posted["MultipleChoiceListField"] == null)
      {
        modèle.MultipleChoiceListField = new string[] { };
      }
      // نمایش فرم
      return View("Formulaire2", modèle);
}

عمل [Action09Post] به جز در دو مورد با عمل [Action08Post] یکسان است:

  • خط ۱۸: ویوی [Formulaire2] به جای ویوی [Formulaire] استفاده می‌شود؛
  • دیگر هیچ پردازشی برای چک‌باکس‌هایی که تیک نخورده‌اند انجام نمی‌شود. این مورد اکنون توسط متد [Html.CheckBoxFor] به درستی مدیریت می‌شود.

5.8. ایجاد فرم از متادیتای مدل

علاوه بر روش‌های ذکر شده در بالا، روش‌های دیگری نیز برای تولید فرم وجود دارد. یکی از این روش‌ها شامل مرتبط کردن اطلاعات با یک فیلد در مدل است که به چارچوب MVC امکان می‌دهد تا تعیین کند کدام تگ ورودی را تولید کند. این اطلاعات به عنوان متادیتا شناخته می‌شوند.

قالب نمای زیر [ViewModel10] را در نظر بگیرید:


using System;
using System.ComponentModel.DataAnnotations;
using System.Drawing;

namespace Exemple_03.Models
{
  public class ViewModel10
  {
    [Display(Name="Text")]
    [DataType(DataType.Text)]
    public string Text { get; set; }

    [Display(Name = "TextArea")]
    [DataType(DataType.MultilineText)]
    public string MultiLineText { get; set; }

    [Display(Name = "Number")]
    public int Number { get; set; }

    [Display(Name = "Decimal")]
    [UIHint("Decimal")]
    public double Decimal { get; set; }

    [Display(Name = "Tel")]
    [DataType(DataType.PhoneNumber)]
    public string Tel { get; set; }

    [Display(Name = "Date")]
    [DataType(DataType.Date)]
    public DateTime Date { get; set; }

    [Display(Name = "Time")]
    [DataType(DataType.Time)]
    public DateTime Time { get; set; }

    [Display(Name = "HiddenInput")]
    [UIHint("HiddenInput")]
    public string HiddenInput { get; set; }

    [Display(Name = "Boolean")]
    [UIHint("Boolean")]
    public bool Boolean { get; set; }

    [Display(Name = "Email")]
    [DataType(DataType.EmailAddress)]
    public string Email{ get; set; }

    [Display(Name = "Url")]
    [DataType(DataType.Url)]
    public string Url { get; set; }

    [Display(Name = "Password")]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Display(Name = "Currency")]
    [DataType(DataType.Currency)]
    public double Currency { get; set; }

    [Display(Name = "CreditCard")]
    [DataType(DataType.CreditCard)]
    public string CreditCard { get; set; }

    // سازنده
    public ViewModel10()
    {
      Text = "tra la la";
      MultiLineText = "ligne1\nligne2";
      Number = 4;
      Decimal = 10.2;
      Tel = "0617181920";
      Date = DateTime.Now;
      Time = DateTime.Now;
      HiddenInput = "caché";
      Boolean = true;
      Email = "x@y.z";
      Url = "http://istia.univ-angers.fr";
      Password = "mdp";
      Currency = 4.2;
      CreditCard = "0123456789012345";
    }
  }
}

متادیتا شامل تگ‌های [Display, DataType, UIHint] است.

این قالب نما با اقدام زیر تولید می‌شود: [Action10Get]:


    // اقدام10-GET
    [HttpGet]
    public ViewResult Action10Get()
    {
      return View(new ViewModel10());
}

در خط ۵ بالا، به اکشن [/First/Action10Get.cshtml ] دستور داده شده است تا قالب نمای نوع [ViewModel10] را نمایش دهد. این نما به شرح زیر است:


@model Exemple_03.Models.ViewModel10

@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action10Get</title>
</head>
<body>
  <h3>Formulaire ASP.NET MVC - 2</h3>
  @using (Html.BeginForm("Action10Post", "First"))
  {
    <table>
      <thead>
        <tr>
          <th>LabelFor</th>
          <th>EditorFor</th>
          <th>DisplayFor</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>@Html.LabelFor(m => m.Text)</td>
          <td>@Html.EditorFor(m => m.Text)</td>
          <td>@Html.DisplayFor(m => m.Text)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.MultiLineText)</td>
          <td>@Html.EditorFor(m => m.MultiLineText)</td>
          <td>@Html.DisplayFor(m => m.MultiLineText)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Number)</td>
          <td>@Html.EditorFor(m => m.Number)</td>
          <td>@Html.DisplayFor(m => m.Number)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Decimal)</td>
          <td>@Html.EditorFor(m => m.Decimal)</td>
          <td>@Html.DisplayFor(m => m.Decimal)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Tel)</td>
          <td>@Html.EditorFor(m => m.Tel)</td>
          <td>@Html.DisplayFor(m => m.Tel)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Date)</td>
          <td>@Html.EditorFor(m => m.Date)</td>
          <td>@Html.DisplayFor(m => m.Date)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Time)</td>
          <td>@Html.EditorFor(m => m.Time)</td>
          <td>@Html.DisplayFor(m => m.Time)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.HiddenInput)</td>
          <td>@Html.EditorFor(m => m.HiddenInput)</td>
          <td>@Html.DisplayFor(m => m.HiddenInput)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Boolean)</td>
          <td>@Html.EditorFor(m => m.Boolean)</td>
          <td>@Html.DisplayFor(m => m.Boolean)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Email)</td>
          <td>@Html.EditorFor(m => m.Email)</td>
          <td>@Html.DisplayFor(m => m.Email)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Url)</td>
          <td>@Html.EditorFor(m => m.Url)</td>
          <td>@Html.DisplayFor(m => m.Url)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Password)</td>
          <td>@Html.EditorFor(m => m.Password)</td>
          <td>@Html.DisplayFor(m => m.Password)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Currency)</td>
          <td>@Html.EditorFor(m => m.Currency)</td>
          <td>@Html.DisplayFor(m => m.Currency)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.CreditCard)</td>
          <td>@Html.EditorFor(m => m.CreditCard)</td>
          <td>@Html.DisplayFor(m => m.CreditCard)</td>
        </tr>
      </tbody>
    </table>
    <input type="submit" value="Valider" />
  }
</body>
</html>

برای هر یک از ویژگی‌های مدل، از متد زیر استفاده می‌کنیم:

  • Html.LabelFor برای نمایش مقدار متادیتای ویژگی [DisplayName
  • Html.EditorFor برای تولید تگ ورودی HTML برای مقدار ویژگی. این روش از متادیتای ویژگی [DataType] و [UIHint] استفاده خواهد کرد؛
  • Html.DisplayFor برای نمایش مقدار ویژگی در قالب مشخص‌شده توسط متادیتای [DataType].

در اینجا مثالی از نحوه کار این روش در مرورگر کروم آورده شده است:

Image

بسته به مرورگر مورد استفاده، ممکن است صفحات متفاوتی نمایش داده شوند. این به این دلیل است که نمای تولید شده از تگ‌های جدیدی که در نسخه ۵ از HTML، معروف به HTML5، معرفی شده‌اند استفاده می‌کند. هنوز همه مرورگرها از این نسخه پشتیبانی نمی‌کنند. همانطور که در بالا نشان داده شده است، مرورگر کروم به طور جزئی از آن پشتیبانی می‌کند.

5.8.1. [POST] برای فرم

فرم [POST] توسط اقدام زیر، [Action10Post]، پردازش می‌شود:


    // Action10-POST
    [HttpPost]
    public ContentResult Action10Post(ViewModel10 modèle)
    {
      string erreurs = getErrorMessagesFor(ModelState);
      string texte = string.Format("Contrôleur={0}, Action={1}, valide={2}, erreurs={3}", RouteData.Values["controller"], RouteData.Values["action"], ModelState.IsValid, erreurs);
      return Content(texte, "text/plain", Encoding.UTF8);
}
  • خط ۳: اکشن [Action10Post] از فرم ارسال‌شده به‌عنوان قالب ورودی خود استفاده می‌کند؛
  • خط ۵: خطاهای اعتبارسنجی این فرم بازیابی می‌شوند؛
  • خط ۶: پاسخ متنی برای مشتری آماده می‌شود؛
  • خط ۷: این ارسال می‌شود.

اکنون بیایید ویژگی‌های قالب [ViewModel10] را یکی‌یکی بررسی کنیم و ببینیم چگونه متاداده‌های مرتبط بر HTML تولیدشده و اعتبارسنجی فیلدهای ورودی تأثیر می‌گذارند.

5.8.2. ویژگی [Text]

تعریف


    [Display(Name="Text")]
    [DataType(DataType.Text)]
    public string Text { get; set; }
...
Text = "tra la la";

نما


      <tr>
        <td>@Html.LabelFor(m => m.Text)</td>
        <td>@Html.EditorFor(m => m.Text)</td>
        <td>@Html.DisplayFor(m => m.Text)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="Text">Text</label></td>
        <td><input class="text-box single-line" id="Text" name="Text" type="text" value="tra la la" /></td>
        <td>tra la la</td>
</tr>

نظرات

  • متد [Html.LabelFor] تگ <label> را در خط ۲ تولید کرد. مقدار ویژگی [for] نام خاصیت پارامتر متد [Html.LabelFor] است.

public string Text { get; set; }

متن نمایش داده شده بین شروع و پایان تگ، متن متادیتا است


[Display(Name="Text")]

متد [Html.LabelFor] همیشه به این صورت عمل می‌کند. ما برای سایر ویژگی‌ها به این موضوع باز نخواهیم گشت.

  • متد [Html.EditorFor] تگ <input> را در خط ۳ تولید کرد. توجه کنید که این تگ دارای یک ویژگی [class] است که کلاس CSS [text-box single-line] را به تگ اختصاص می‌دهد. ویژگی‌های [id] و [name] به عنوان مقدار خود نام [Text] از ویژگی پارامتر متد [Html.EditorFor] را دارند. ویژگی [type] به دلیل متادیتا مقدار [text] را دریافت کرد.

[DataType(DataType.Text)]
  • روش [Html.DisplayFor] متن را در خط 4 تولید کرد. این مقدار ویژگی پارامتر روش [Html.DisplayFor ] است. این روش تحت تأثیر متادیتا قرار دارد

[DataType(DataType.Text)]

که باعث می‌شود مقدار به صورت متن بدون قالب‌بندی نمایش داده شود.

5.8.3. ویژگی [MultiLineText]

تعریف


    [Display(Name = "TextArea")]
    [DataType(DataType.MultilineText)]
public string MultiLineText { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.MultiLineText)</td>
        <td>@Html.EditorFor(m => m.MultiLineText)</td>
        <td>@Html.DisplayFor(m => m.MultiLineText)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="MultiLineText">TextArea</label></td>
        <td><textarea class="text-box multi-line" id="MultiLineText" name="MultiLineText">
ligne1
ligne2</textarea></td>
        <td>ligne1
ligne2</td>
</tr>

نظرات

  • متد [Html.EditorFor] تگ <textarea> را در خط ۳ تولید کرد. توجه کنید که این تگ دارای ویژگی [class] است که کلاس CSS [text-box multi-line] را به تگ اختصاص می‌دهد. ویژگی‌های [id] و [name] به عنوان مقدار خود، نام [MultiLineText] از خاصیت پارامتر متد [Html.EditorFor] را دارند. این همیشه صادق است. ما دیگر این را ذکر نخواهیم کرد. تگ تولیدشده <textarea> است به دلیل متادیتا

[DataType(DataType.MultilineText)]

که مشخص می‌کرد این ویژگی متن چندخطی است.

  • متد [Html.DisplayFor] متن مربوط به خطوط ۴–۵ را تولید کرد. این مقدارِ ویژگی پارامترِ متد [Html.DisplayFor ] است.

5.8.4. ویژگی [Number]

تعریف


    [Display(Name = "Number")]
public int Number { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Number)</td>
        <td>@Html.EditorFor(m => m.Number)</td>
        <td>@Html.DisplayFor(m => m.Number)</td>
</tr>

نمای بصری

 

HTML تولید شد


<tr>
        <td><label for="Number">Number</label></td>
        <td><input class="text-box single-line" data-val="true" data-val-number="Le champ Number doit être un nombre." data-val-required="Le champ Number est requis." id="Number" name="Number" type="number" value="4" /></td>
        <td>4</td>
      </tr>

نظرات

  • متد [Html.EditorFor] تگ <input> را در خط ۳ با یک ویژگی [type] از نوع [number] تولید کرد. ظاهراً صرفاً به این دلیل که این ویژگی از نوع [int] است. ویژگی‌های [data-val]، [data-val-number] و [data-val-required] توسط HTML5 شناسایی نمی‌شوند. آنها توسط یک چارچوب اعتبارسنجی داده‌های جاوااسکریپت سمت کلاینت استفاده می‌شوند؛
  • متد [Html.DisplayFor] متن را در خط ۴ تولید کرد، مقدار ویژگی.

اعتبارسنجی

ویژگی‌های [data-x] بر اعتبارسنجی داده‌ها در سمت کلاینت تأثیر می‌گذارند. در اینجا دو مثال آورده شده است:

یک عدد نادرست وارد و اعتبارسنجی می‌شود:

 

در مثال بالا، اعتبارسنجی در سمت کلاینت انجام شد. فرم تا زمانی که خطا اصلاح نشود ارسال نخواهد شد.

مثال دیگر: هیچ چیزی وارد نشده است:

در مثال بالا، [Action10Post] یک خطا را نشان می‌دهد. شاید به یاد داشته باشید که ما قبلاً این رفتار را با استفاده از ویژگی [Required] بر روی خصوصیتی که باید بررسی شود (به صفحه ۶۹ مراجعه کنید)، در این مورد خصوصیت [Number]، به دست آورده بودیم. در اینجا نیازی به انجام این کار نبود.

5.8.5. ویژگی [Decimal]

تعریف


    [Display(Name = "Decimal")]
    [UIHint("Decimal")]
public double Decimal { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Decimal)</td>
        <td>@Html.EditorFor(m => m.Decimal)</td>
        <td>@Html.DisplayFor(m => m.Decimal)</td>
</tr>

نمای بصری

 

HTML تولید شد


      <tr>
        <td><label for="Decimal">Decimal</label></td>
        <td><input class="text-box single-line" data-val="true" data-val-number="Le champ Decimal doit être un nombre." data-val-required="Le champ Decimal est requis." id="Decimal" name="Decimal" type="text" value="10,20" /></td>
        <td>10,20</td>
</tr>

نظرات

  • متد [Html.EditorFor] تگ <input> را در خط ۳ با یک ویژگی [type] از نوع [text] تولید کرد. سایر ویژگی‌ها با ویژگی‌های تولیدشده برای خاصیت قبلی [Number] یکسان هستند. متادیتا:

[UIHint("Decimal")]

به این معنی است که مقدار ویژگی با دو رقم اعشاری برای هر دو روش [Html.EditorFor] و [Html.DisplayFor] نمایش داده می‌شود.

اعتبارسنجی

برخلاف مورد قبلی، هیچ خطای اعتبارسنجی در سمت کلاینت گزارش نمی‌شود. خطا تنها توسط اکشن [Action10Post] گزارش می‌شود. در اینجا نیز، عدد اعشاری بدون نیاز به تنظیم ویژگی [Required] الزامی است.

5.8.6. ویژگی [Tel]

تعریف


    [Display(Name = "Tel")]
    [DataType(DataType.PhoneNumber)]
public string Tel { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Tel)</td>
        <td>@Html.EditorFor(m => m.Tel)</td>
        <td>@Html.DisplayFor(m => m.Tel)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="Tel">Tel</label></td>
        <td><input class="text-box single-line" id="Tel" name="Tel" type="tel" value="0617181920" /></td>
        <td>0617181920</td>
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [tel] تولید کرد. این مقدار به دلیل متادیتا تولید شد:

[DataType(DataType.PhoneNumber)]

نوع [tel] برای تگ <input> یک ویژگی جدید است که در HTML5 معرفی شده است. مرورگر کروم آن را به عنوان یک تگ <input> با نوع [text] در نظر گرفت.

اعتبارسنجی

هیچ خطای اعتبارسنجی در سمت کلاینت یا سرور گزارش نشده است. شما می‌توانید هر چیزی را وارد کنید.

5.8.7. ویژگی [Date]

تعریف


    [Display(Name = "Date")]
    [DataType(DataType.Date)]
public DateTime Date { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Date)</td>
        <td>@Html.EditorFor(m => m.Date)</td>
        <td>@Html.DisplayFor(m => m.Date)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="Date">Date</label></td>
        <td><input class="text-box single-line" data-val="true" data-val-date="Le champ Date doit être une date." data-val-required="Le champ Date est requis." id="Date" name="Date" type="date" value="11/10/2013" /></td>
        <td>11/10/2013</td>
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [date] تولید کرد. این مقدار به دلیل متادیتا تولید شد:

[DataType(DataType.Date)]

نوع [date] برای تگ <input> یک ویژگی جدید (HTML5) است. مرورگر کروم آن را تشخیص می‌دهد و امکان وارد کردن تاریخ با استفاده از یک تقویم را فراهم می‌کند. علاوه بر این، تاریخ وارد شده در قالب [jj/mm/aaaa] نمایش داده می‌شود، یعنی کروم فرمت تاریخ را با فرمت مرورگر تطبیق می‌دهد.

  • روش [Html.DisplayFor] نیز تاریخ را به شکل [jj/mm/aaaa] نوشت، که این بار نیز به دلیل وجود متادیتای [Date] بود.

اعتبارسنجی

تاریخ نامعتبر در سمت کلاینت ([1]) علامت‌گذاری می‌شود و از ارسال فرم (POST) به سرور جلوگیری می‌کند.

عدم وجود تاریخ در سمت کلاینت علامت‌گذاری نمی‌شود اما در سمت سرور علامت‌گذاری می‌شود: [2].

5.8.8. ویژگی [Time]

تعریف


    [Display(Name = "Time")]
    [DataType(DataType.Time)]
public DateTime Time { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Time)</td>
        <td>@Html.EditorFor(m => m.Time)</td>
        <td>@Html.DisplayFor(m => m.Time)</td>
</tr>

نمای بصری

 

HTML تولید شد


      <tr>
        <td><label for="Time">Time</label></td>
        <td><input class="text-box single-line" data-val="true" data-val-required="Le champ Time est requis." id="Time" name="Time" type="time" value="11:17" /></td>
        <td>11:17</td>
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [time] تولید کرد. این مقدار به دلیل متادیتا تولید شد:

[DataType(DataType.Time)]

نوع [time] برای تگ <input> یک ویژگی جدید است که در HTML5 معرفی شده است. مرورگر کروم آن را تشخیص می‌دهد و اجازه می‌دهد زمان به صورت قالب [hh:mm] وارد شود؛

  • روش [Html.DisplayFor] نیز زمان را در قالب [hh:mm] ثبت می‌کند، که این بار نیز به دلیل وجود متادیتای [Time] است.

اعتبارسنجی

از نظر فنی امکان وارد کردن زمان نامعتبر وجود ندارد. عدم وجود زمان در سمت سرور علامت‌گذاری می‌شود:

 

5.8.9. ویژگی [HiddenInput]

تعریف


    [Display(Name = "HiddenInput")]
    [UIHint("HiddenInput")]
public string HiddenInput { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.HiddenInput)</td>
        <td>@Html.EditorFor(m => m.HiddenInput)</td>
        <td>@Html.DisplayFor(m => m.HiddenInput)</td>
</tr>

نمای بصری

 

HTML تولید شد


      <tr>
        <td><label for="HiddenInput">HiddenInput</label></td>
        <td>cach&#233;<input id="HiddenInput" name="HiddenInput" type="hidden" value="hidden" /></td>
        <td>cach&#233;
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [hidden] تولید کرد، یعنی یک فیلد مخفی (اما با این وجود ارسال‌شده). این مقدار به دلیل متادیتا تولید شد:

[UIHint("HiddenInput")]
  • متد [Html.DisplayFor] مقدار فیلد مخفی را نوشت.

5.8.10. ویژگی [Boolean]

تعریف


    [Display(Name = "Boolean")]
public bool Boolean { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Boolean)</td>
        <td>@Html.EditorFor(m => m.Boolean)</td>
        <td>@Html.DisplayFor(m => m.Boolean)</td>
</tr>

تصویر

 

HTML تولید شد


      <tr>
        <td><label for="Boolean">Boolean</label></td>
        <td><input checked="checked" class="check-box" data-val="true" data-val-required="Le champ Boolean est requis." id="Boolean" name="Boolean" type="checkbox" value="true" /><input name="Boolean" type="hidden" value="false" /></td>
        <td><input checked="checked" class="check-box" disabled="disabled" type="checkbox" /></td>
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با یک ویژگی [type] از نوع [checkbox]، یعنی یک چک‌باکس، تولید کرد. این مقدار تولید شد زیرا این ویژگی از نوع بولین است:

public bool Boolean { get; set; }
  • متد [Html.DisplayFor] خط ۴ را تولید کرد، که آن نیز یک تیک‌باکس (ویژگی type) اما غیرفعال (ویژگی disabled) بود.

5.8.11. ویژگی [Email]

تعریف


    [Display(Name = "Email")]
    [DataType(DataType.EmailAddress)]
public string Email{ get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Email)</td>
        <td>@Html.EditorFor(m => m.Email)</td>
        <td>@Html.DisplayFor(m => m.Email)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="Email">Email</label></td>
        <td><input class="text-box single-line" id="Email" name="Email" type="email" value="x@y.z" /></td>
        <td><a href="mailto:x@y.z">x@y.z</a></td>
</tr>

نظرات

  • متد [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [email] تولید کرد. این نوع در HTML5 جدید است. این نوع به دلیل متادیتا تولید شده است:

[DataType(DataType.EmailAddress)]

به نظر می‌رسد کروم این نوع را به عنوان یک نوع [text] در نظر گرفته است.

  • متد [Html.DisplayFor] در خط ۴ تولید شد: یک لینک به آدرس ایمیل.

اعتبارسنجی

یک آدرس نامعتبر در سمت کلاینت [1] گزارش شده است:

خالی گذاشتن یک فیلد خطا ایجاد نمی‌کند.

5.8.12. ویژگی [Url]

تعریف


    [Display(Name = "Url")]
    [DataType(DataType.Url)]
public string Url { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Url)</td>
        <td>@Html.EditorFor(m => m.Url)</td>
        <td>@Html.DisplayFor(m => m.Url)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="Url">Url</label></td>
        <td><input class="text-box single-line" id="Url" name="Url" type="url" value="http://istia.univ-angers.fr" /></td>
        <td><a href="http://istia.univ-angers.fr">http://istia.univ-angers.fr
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [url] تولید کرد. این نوع در HTML5 جدید است. این تگ به دلیل متادیتا تولید شد:

[DataType(DataType.Url)]

به نظر می‌رسد کروم این نوع را به عنوان یک نوع [text] در نظر می‌گیرد.

  • متد [Html.DisplayFor] خط ۴ را تولید کرد: یک لینک به URL.

اعتبارسنجی

یک URL نامعتبر در سمت کلاینت به‌عنوان [1] گزارش شده است:

خالی گذاشتن این فیلد خطا ایجاد نمی‌کند.

5.8.13. ویژگی [Password]

تعریف


    [Display(Name = "Password")]
    [DataType(DataType.Password)]
public string Password { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Password)</td>
        <td>@Html.EditorFor(m => m.Password)</td>
        <td>@Html.DisplayFor(m => m.Password)</td>
</tr>

نمای بصری

 

HTML تولید شد


      <tr>
        <td><label for="Password">Password</label></td>
        <td><input class="text-box single-line password" id="Password" name="Password" type="password" value="mdp" /></td>
        <td>mdp</td>
</tr>

نظرات

  • روش [Html.EditorFor] تگ <input> را در خط ۳ با ویژگی [type] از نوع [password] تولید کرد. این نوع به دلیل متادیتا تولید شد:

[DataType(DataType.Password)]
  • روش [Html.DisplayFor] خط ۴ را تولید کرد.

5.8.14. ویژگی [Currency]

تعریف


    [Display(Name = "Currency")]
    [DataType(DataType.Currency)]
public double Currency { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.Currency)</td>
        <td>@Html.EditorFor(m => m.Currency)</td>
        <td>@Html.DisplayFor(m => m.Currency)</td>
</tr>

نمای بصری

 

HTML تولید شد


      <tr>
        <td><label for="Currency">Currency</label></td>
        <td><input class="text-box single-line" data-val="true" data-val-number="Le champ Currency doit être un nombre." data-val-required="Le champ Currency est requis." id="Currency" name="Currency" type="text" value="4,2" /></td>
        <td>4,20 €</td>
</tr>

نظرات

  • متد [Html.EditorFor] در خط ۳ تگ <input> را با یک ویژگی [type] از نوع [text] تولید کرد؛
  • روش [Html.DisplayFor] خط ۴ را تولید کرد، عددی با دو اعشار و یک نماد ارز. این فرمت به دلیل متادیتا استفاده شد:

[DataType(DataType.Currency)]

اعتبارسنجی

یک مقدار نامعتبر ([1]) یا مقدار مفقود ([2]) در سمت سرور گزارش می‌شود:

5.8.15. ویژگی [CreditCard]

تعریف


    [Display(Name = "CreditCard")]
    [DataType(DataType.CreditCard)]
public string CreditCard { get; set; }

نما


      <tr>
        <td>@Html.LabelFor(m => m.CreditCard)</td>
        <td>@Html.EditorFor(m => m.CreditCard)</td>
        <td>@Html.DisplayFor(m => m.CreditCard)</td>
</tr>

نمایشی

 

HTML تولید شد


      <tr>
        <td><label for="CreditCard">CreditCard</label></td>
        <td><input class="text-box single-line" id="CreditCard" name="CreditCard" type="text" value="0123456789012345" /></td>
        <td>0123456789012345</td>
</tr>

نظرات

  • متد [Html.EditorFor] در خط ۳ تگ <input> را با یک ویژگی [type] از نوع [text] تولید کرد. روش [Html.DisplayFor] خط ۴ را تولید کرد. در اینجا مشخص نیست که متادیتا چه نقشی ایفا می‌کند:

[DataType(DataType.CreditCard)]

اعتبارسنجی

هیچ اعتبارسنجی‌ای انجام نمی‌شود، نه در سمت کلاینت و نه در سمت سرور.

5.9. اعتبارسنجی فرم

ما پیش‌تر مسئله اعتبارسنجی مدل یک اکشن را در بخش 4.5 و بخش‌های بعدی مورد بررسی قرار داده‌ایم. در اینجا به این موضوع در زمینه یک فرم بازمی‌گردیم:

  • چگونه کاربر را از خطاهای ورودی مطلع کنیم؛
  • انجام اعتبارسنجی هم در سمت کلاینت و هم در سمت سرور به منظور اطلاع‌رسانی سریع‌تر خطاها به کاربر.

5.9.1. اعتبارسنجی سمت سرور

بیایید مدل زیر را در نظر بگیریم:


using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net.Mail;

namespace Exemple_03.Models
{
  public class ViewModel11 : IValidatableObject
  {

    [Required(ErrorMessage = "Information requise")]
    [Display(Name = "Chaîne d'au moins quatre caractères")]
    [RegularExpression(@"^.{4,}$", ErrorMessage = "Information incorrecte")]
    public string Chaine1 { get; set; }

    [Display(Name = "Chaîne d'au plus quatre caractères")]
    [Required(ErrorMessage = "Information requise")]
    [RegularExpression(@"^.{1,4}$", ErrorMessage = "Information incorrecte")]
    public string Chaine2 { get; set; }

    [Required(ErrorMessage = "Information requise")]
    [Display(Name = "Chaîne de quatre caractères exactement")]
    [RegularExpression(@"^.{4,4}$", ErrorMessage = "Information incorrecte")]
    public string Chaine3 { get; set; }

    [Required(ErrorMessage = "Information requise")]
    [Display(Name = "Nombre entier")]
    public int Entier1 { get; set; }

    [Display(Name = "Nombre entier dans l'intervalle [1,100]")]
    [Required(ErrorMessage = "Information requise")]
    [Range(1, 100, ErrorMessage = "Information incorrecte")]
    public int Entier2 { get; set; }

    [Display(Name = "Nombre réel")]
    [Required(ErrorMessage = "Information requise")]
    public double Reel1 { get; set; }

    [Display(Name = "Nombre réel dans l'intervalle [10.2, 11.3]")]
    [Required(ErrorMessage = "Information requise")]
    [Range(10.2, 11.3, ErrorMessage = "Information incorrecte")]
    public double Reel2 { get; set; }

    [Display(Name = "Adresse mail")]
    [Required(ErrorMessage = "Information requise")]
    public string Email1 { get; set; }

    [Display(Name = "Date sous la forme dd/jj/aaaa")]
    [RegularExpression(@"\s*\d{2}/\d{2}/\d{4}\s*", ErrorMessage = "Information incorrecte")]
    [Required(ErrorMessage = "Information requise")]
    public string Regexp1 { get; set; }

    [Display(Name = "Date postérieure à celle d'aujourd'hui")]
    [Required(ErrorMessage = "Information requise")]
    [DataType(DataType.Date)]
    public DateTime Date1 { get; set; }

    //اعتبارسنجی
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
      List<ValidationResult> résultats = new List<ValidationResult>();
      // تاریخ ۱
      if (Date1.Date <= DateTime.Now.Date)
      {
        résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Date1" }));
      }
      // ایمیل۱
      try
      {
        new MailAddress(Email1);
      }
      catch
      {
        résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Email1" }));
      }
      // فهرست خطاها را بازمی‌گرداند
      return résultats;
    }
  }
}

این قالب توسط نمای زیر، [Action11Get.cshtml]، نمایش داده خواهد شد:


@model Exemple_03.Models.ViewModel11
@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action11Get</title>
  <link rel="stylesheet" href="~/Content/Site.css" />
</head>
<body>
  <h3>Formulaire ASP.NET MVC – Validation 1</h3>
  @using (Html.BeginForm("Action11Post", "First"))
  {
    <table>
      <thead>
        <tr>
          <th>Type attendu</th>
          <th>Valeur saisie</th>
          <th>Message d'erreur</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>@Html.LabelFor(m => m.Chaine1)</td>
          <td>@Html.EditorFor(m => m.Chaine1)</td>
          <td>@Html.ValidationMessageFor(m => m.Chaine1)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Chaine2)</td>
          <td>@Html.EditorFor(m => m.Chaine2)</td>
          <td>@Html.ValidationMessageFor(m => m.Chaine2)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Chaine3)</td>
          <td>@Html.EditorFor(m => m.Chaine3)</td>
          <td>@Html.ValidationMessageFor(m => m.Chaine3)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Entier1)</td>
          <td>@Html.EditorFor(m => m.Entier1)</td>
          <td>@Html.ValidationMessageFor(m => m.Entier1)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Entier2)</td>
          <td>@Html.EditorFor(m => m.Entier2)</td>
          <td>@Html.ValidationMessageFor(m => m.Entier2)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Reel1)</td>
          <td>@Html.EditorFor(m => m.Reel1)</td>
          <td>@Html.ValidationMessageFor(m => m.Reel1)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Reel2)</td>
          <td>@Html.EditorFor(m => m.Reel2)</td>
          <td>@Html.ValidationMessageFor(m => m.Reel2)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Email1)</td>
          <td>@Html.EditorFor(m => m.Email1)</td>
          <td>@Html.ValidationMessageFor(m => m.Email1)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Regexp1)</td>
          <td>@Html.EditorFor(m => m.Regexp1)</td>
          <td>@Html.ValidationMessageFor(m => m.Regexp1)</td>
        </tr>
        <tr>
          <td>@Html.LabelFor(m => m.Date1)</td>
          <td>@Html.EditorFor(m => m.Date1)</td>
          <td>@Html.ValidationMessageFor(m => m.Date1)</td>
        </tr>
      </tbody>
    </table>
    <p>
      <input type="submit" value="Valider" />
    </p>
  }
</body>
</html>
  • خط ۱۲: به شیوه‌نامه [Site.css] ارجاع داده شده است. به طور پیش‌فرض، این شیوه‌نامه شامل کلاس‌هایی است که برای برجسته‌سازی خطاهای ورودی فرم استفاده می‌شوند؛
  • خطوط ۱۸–۲۵: یک جدول سه‌ستونی:
    • ستون ۱ متن را با استفاده از روش [Html.LabelFor] نمایش می‌دهد،
    • ستون ۲ ورودی را با استفاده از روش [Html.EditorFor] نمایش می‌دهد،
    • ستون ۳ هرگونه خطای ورودی را با استفاده از روش [Html.ValidationMessageFor] نمایش می‌دهد؛

عمل [Action11Get] برای نمایش فرم استفاده می‌شود:


    // Action11-GET
    [HttpGet]
    public ViewResult Action11Get()
    {
      return View("Action11Get", new ViewModel11());
}

عمل [Action11Post] برای نمایش مجدد فرم و نشان دادن هرگونه خطای ورودی استفاده می‌شود:


    // Action11-POST
    [HttpPost]
    public ViewResult Action11Post(ViewModel11 modèle)
    {
      return View("Action11Get", modèle);
}
  • خط ۳: قالب [ViewModel11] ایجاد شده و سپس با مقادیر ارسال‌شده مقداردهی اولیه می‌شود. سپس ممکن است خطاهایی رخ دهد. برای هر ویژگی نادرست P در قالب، یک پیام خطا مرتبط است. این پیام توسط متد [Html.ValidationMessageFor] فرم بازگردانده می‌شود.

در اینجا مثالی از اجرا آورده شده است:

در اینجا یک مثال دیگر آورده شده است:

 

توجه کنید که هر دو تاریخ نادرست هستند (امروز ۱۱/۱۰/۲۰۱۳ است) اما خطاها علامت‌گذاری نشده‌اند. این خطاها توسط متد [Validate] در مدل تشخیص داده می‌شوند:


    // اعتبارسنجی
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
      List<ValidationResult> résultats = new List<ValidationResult>();
      // تاریخ 1
      if (Date1.Date <= DateTime.Now.Date)
      {
        résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Date1" }));
      }
      // Email1
      try
      {
        new MailAddress(Email1);
      }
      catch
      {
        résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Email1" }));
      }
      // Regexp1
      try
      {
        DateTime.ParseExact(Regexp1, "dd/MM/yyyy", CultureInfo.CreateSpecificCulture("fr-FR"));
      }
      catch
      {
        résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Regexp1" }));
      }

      // فهرست خطاها را بازمی‌گرداند
      return résultats;
}

روش [Validate] تنها پس از گذراندن تمام اعتبارسنجی‌های ویژگی‌ها اجرا می‌شود. این موضوع با یک مثال نهایی نشان داده شده است:

 

5.9.2. اعتبارسنجی سمت کلاینت

تمام اعتبارسنجی‌های قبلی روی سرور انجام می‌شدند. بنابراین برای مطلع شدن کاربر از خطاهایش، یک رفت و برگشت بین کلاینت و سرور ضروری است. اعتبارسنجی سمت کلاینت با استفاده از کد جاوااسکریپت، کاربر را در اسرع وقت و در هر صورت قبل از POST از خطاهایش آگاه می‌کند. این کار تنها پس از اصلاح تمام خطاهای شناسایی‌شده امکان‌پذیر است.

ما در حال استفاده مجدد از قالب قبلی [ViewModel11] هستیم، اما اکنون آن را با نمای زیر [Action12Get.cshtml] نمایش می‌دهیم:


@model Exemple_03.Models.ViewModel11
@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action12Get</title>
  <link rel="stylesheet" href="~/Content/Site.css" />
  <script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js" ></script>
  <script type="text/javascript" src="~/Scripts/jquery.validate.min.js" ></script>
  <script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js" ></script>
</head>
<body>
  <h3>Formulaire ASP.NET MVC - Validation 1</h3>
  @using (Html.BeginForm("Action11Post", "First"))
  {
    <table>
      <thead>
        <tr>
          <th>Type attendu</th>
          <th>Valeur saisie</th>
          <th>Message d'erreur</th>
        </tr>
      </thead>
      <tbody>
...
      </tbody>
    </table>
    <p>
      <input type="submit" value="Valider" />
    </p>
  }
</body>
</html>

توجه: خط ۱۳ – نسخه jQuery را با نسخه‌ای که در کپی Visual Studio خود دارید تطبیق دهید (به زیر مراجعه کنید).

اعتبارسنجی سمت کلاینت نیاز دارد که خط ۳ زیر در فایل [Web.config] برنامه وجود داشته باشد.


  <appSettings>
    ...
    <add key="ClientValidationEnabled" value="true" />
</appSettings>
  • خطوط ۱–۴: بخش [appSettings] باید فرزند مستقیم بخش [configuration] در فایل [Web.config] باشد؛

نما [Action12Get] دقیقاً مشابه نمای قبلی [Action11Get] است، به جز خطوط ۱۳ تا ۱۵. این خطوط شامل اسکریپت‌های جاوااسکریپت مورد نیاز برای اعتبارسنجی سمت کلاینت در نما هستند. این اسکریپت‌ها در پوشه [Scripts] درون پروژه قرار دارند:

هر اسکریپت یک نسخهٔ عادی ([.js]) و یک نسخهٔ فشرده‌شده ([min.js]) دارد. نسخهٔ دوم کوچکتر اما غیرقابل‌خواندن است. از آن در محیط تولید استفاده می‌شود. نسخهٔ قابل‌خواندن در محیط توسعه استفاده می‌شود.

ویوی [Action12Get.cshtml] توسط اقدام زیر [Action12Get] نمایش داده خواهد شد:


    // Action12-GET
    [HttpGet]
    public ViewResult Action12Get()
    {
      return View("Action12Get", new ViewModel11());
}

فرم وارد شده توسط اقدام زیر پردازش خواهد شد: [Action12Post]:


    // Action12-POST
    [HttpPost]
    public ViewResult Action12Post(ViewModel11 modèle)
    {
      return View("Action12Get", modèle);
}

بیایید یک مثال را بررسی کنیم تا ببینیم این تغییرات چه تأثیری دارد:

به محض اینکه یک کاراکتر را در [1] تایپ می‌کنید، پیام در [2] ظاهر می‌شود زیرا مقدار مورد انتظار باید حداقل چهار کاراکتر باشد. بنابراین اعتبارسنجی هر بار که یک کاراکتر جدید تایپ می‌شود، انجام می‌گیرد. پیام خطا پس از تایپ چهارمین کاراکتر ناپدید می‌شود. پس از انجام این کار، بیایید فرم را ارسال کنیم:

پیام‌های URL و [3] به ما نشان می‌دهند که [POST] رخ نداده است. با این حال، کلیک روی دکمه [Valider] تمام اعتبارسنجی‌های سمت کلاینت را فعال کرد و پیام‌های خطای جدیدی ظاهر شدند.

بیایید نگاهی بیندازیم به HTML تولیدشده برای اولین ورودی، برای مثال:


        <tr>
          <td><label for="Chaine1">Cha&#238;باید حداقل چهار کاراکتر باشد</label></td>
          <td><input class="text-box single-line" data-val="true" data-val-regex="Information incorrecte" data-val-regex-pattern="^.{4,}$" data-val-required="Information requise" id="Chaine1" name="Chaine1" type="text" value="" /></td>
          <td><span class="field-validation-valid" data-valmsg-for="Chaine1" data-valmsg-replace="true"></span></td>
</tr>
  • در خط ۳ می‌بینیم:
    • پیام خطا برای زمانی که یک ورودی وجود ندارد: [data-val-required],
    • پیام خطا برای یک ورودی نادرست: [data-val-regex],
    • بیان منظم برای رشته وارد شده [data-val-regex-pattern];
  • خط ۴، ویژگی‌های دیگر [data-x] که برای نمایش هرگونه پیام خطا استفاده می‌شوند؛

ویژگی‌های [data-x] تگ‌های تولیدشده توسط جاوااسکریپتی که در ویو جاسازی کرده‌ایم، مورد استفاده قرار می‌گیرند. اگر این ویژگی‌ها وجود نداشته باشند، به سادگی نادیده گرفته می‌شوند و در نتیجه هیچ اعتبارسنجی سمت کلاینت انجام نمی‌شود. این تکنیک به همان شیوه‌ای عمل می‌کند که در مثال قبلی دیدیم. از این رو، برای این تکنیک از اصطلاح [unobtrusive] استفاده می‌شود.

5.10. مدیریت لینک‌های ناوبری و اقدام

ما دو نمای زیر را ایجاد می‌کنیم تا نشان دهیم که چگونه لینک‌ها در یک نما مدیریت می‌شوند:

  • در [1] و [2]، دو پیوند ناوبری وجود دارد؛
  • در [3] یک لینک عملیاتی وجود دارد که فرم را ارسال می‌کند. این لینک برای ناوبری استفاده نمی‌شود.

صفحه ۱ توسط نمای زیر، [Action16Get.cshtml]، تولید می‌شود:


@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action16Get</title>
  <script>
    function postForm() {
      //فرم را از سند بازیابی می‌کند
      var form = document.forms[0];
      //ارسال
      form.submit();
    }
  </script>
</head>
<body>
  <h3>Navigation - page 1</h3>
  <h4>@ViewBag.info</h4>
  @using (Html.BeginForm("Action16Post", "Second"))
  {
    @Html.Label("data", "Tapez un texte")
    @Html.TextBox("data")
    <a href="javascript:postForm()">Valider</a>
  }
  <p>
    @Html.ActionLink("Page 2", "Action17Get", "Second")
  </p>
</body>
</html>
  • خط ۲۲: اطلاعاتی که توسط عملی که نما را بازمی‌گرداند، اولیه می‌شود؛
  • خطوط ۲۳–۲۸: یک فرم؛
  • خط ۲۵: یک برچسب برای فیلد [data];
  • خط ۲۶: یک فیلد ورودی با نام [data];
  • خط ۲۷: یک لینک از نوع [submit]. با کلیک بر روی آن، تابع جاوااسکریپت [postForm] اجرا می‌شود (ویژگی href). این تابع در خطوط ۱۲ تا ۱۷ تعریف شده است؛
  • خط ۱۴: یک مرجع برای اولین فرم در سند، همان فرمِ خط ۲۳، بازیابی می‌شود؛
  • خط ۱۶: این فرم ارسال می‌شود. در نهایت، گویی دکمه‌ای از نوع [submit] کلیک شده است. فرم به کنترلر و اکشن مشخص‌شده در خط ۲۳ ارسال می‌شود؛
  • خط ۳۰: یک لینک ناوبری. کد تولیدشده HTML به شرح زیر است:

    <a href="/Second/Action17Get">Page 2</a>

متد مورد استفاده ActionLink(Text, Action, Controller) است.

صفحه ۲ توسط نمای زیر تولید می‌شود: [Action17Get.cshtml]:


@{
  Layout = null;
}

<!DOCTYPE html>

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Action17Get</title>
</head>
<body>
  <h3>Navigation - Page 2</h3>
  <h4>@ViewBag.info</h4>
  <p>
    @Html.ActionLink("Page 1", "Action16Get", "Second")
  </p>
</body>
</html>

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


      // Action16-GET
      [HttpGet]
      public ViewResult Action16Get()
      {
        ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
        return View("Action16Get");
      }

      // Action16-POST
      [HttpPost]
      public ViewResult Action16Post(string data)
      {
        ViewBag.info = string.Format("Contrôleur={0}, Action={1}, Data={2}", RouteData.Values["controller"], RouteData.Values["action"], data);
        return View("Action16Get");
      }

      // Action17-GET
      [HttpGet]
      public ViewResult Action17Get()
      {
        ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
        return View();
}
  • خط ۶: اکشن [Action16Get] نما [Action16Get.cshtml] را تولید می‌کند، یعنی صفحه ۱ مثال. این نما بر اساس [ViewBag] (خط ۵) است؛
  • خط ۱۹: عمل [Action17Get] نما [Action17Get.cshtml] را تولید می‌کند، یعنی صفحه ۲ مثال. این نما بر اساس [ViewBag] (خط ۲۱) است؛
  • خط ۱۱: اکشن [Action16PostPOST را از فرمِ نما [Action16Get.cshtml] پردازش می‌کند. این اکشن پارامتر با نام [data] را دریافت می‌کند. به یاد داشته باشید که این نام فیلد ورودی در فرم است؛
  • خط ۱۳: اطلاعاتی وارد [ViewBag] می‌شود؛
  • خط ۱۴: نمای [Action16Get.cshtml] نمایش داده می‌شود.

از خوانندگان دعوت می‌شود این مثال را امتحان کنند.