PHP سریعتر از ASP.NET! افسانه یا واقعیت؟
یک دست سازی ی و ک دریافتی در صفحات وب
- Grid Panel
- Stack Panel
- Dock Panel
- Wrap Panel
- Canvas Panel
StackPanel
<StackPanel> <TextBlock Margin="10" FontSize="20">How do you like your coffee?</TextBlock> <Button Margin="10">Black</Button> <Button Margin="10">With milk</Button> <Button Margin="10">Latte machiato</Button> <Button Margin="10">Chappuchino</Button> </StackPanel>
نکتهی مهم اینکه میتوانید در اینجا از یک nested layout هم استفاده کنید بدین صورت که یک layout را داخل یک layout دیگر قرار دهید. کد زیر ترکیب دو stack panel را به صورت افقی و عمودی به ما نشان میدهد:
<StackPanel Orientation="Vertical"> <!-- Vertical is the default --> <Label Background="Red">Red 1</Label> <Label Background="LightGreen">Green 1</Label> <StackPanel Orientation="Horizontal"> <Label Background="Red">Red 2</Label> <Label Background="LightGreen">Green 2</Label> <Label Background="LightBlue">Blue 2</Label> <Label Background="Yellow">Yellow 2</Label> <Label Background="Orange">Orange 2</Label> </StackPanel> <Label Background="LightBlue">Blue 1</Label> <Label Background="Yellow">Yellow 1</Label> <Label Background="Orange">Orange 1</Label> </StackPanel>
Dock Panel
احتمالا به خاطر نامش، نحوه کارش را حدس زده اید. این پنل، اشیاء موجود را در 4 جهت و مرکز میچسباند. مشخص نمودن جهت چسبیده شدن هر کنترل توسط خاصیت DockPanel.Dock صورت میگیرد و مقدار Left، مقدار پیش فرض است. در صورتی که بخواهید المانی را در مرکز بچسبانید باید آن را به عنوان آخرین المان معرفی کرده و در Dock Panel مقدار خاصیت LastChildFill را با True برابر کنید.
<DockPanel LastChildFill="True"> <Button Content="Dock=Top" DockPanel.Dock="Top"/> <Button Content="Dock=Bottom" DockPanel.Dock="Bottom"/> <Button Content="Dock=Left"/> <Button Content="Dock=Right" DockPanel.Dock="Right"/> <Button Content="LastChildFill=True"/> </DockPanel>
به نحوهی تعریف خاصیت DockPanel.Dock دقت کنید به این نوع خاصیتها، Attached Dependency Property (شاید در فارسی بتوانیم خاصیتهای وابستگی متصل صدا بزنیم) میگویند. این خاصیتها نوع خاصی از خاصیتهای وابستگی هستند که به شما اجازه میدهند مقداری را به شیءایی نسبت دهید که آن شیء چیزی در مورد آن نمیداند. بهترین مثال در مورد این ویژگی، پنلها هستند که یکی از موارد استفادهی از آن را در بالا میبینید. هر پنل میتواند تا بی نهایت المان فرزند داشته باشد که هر المان باید خواصش توسط پنل مشخص گردد. ولی اگر پنل ما تعداد زیادی فرزند داشته باشد، نوشتن خواص هر کدام از فرزندها داخل تگ پنل، کاری غیر ممکن است. اینجاست که این نوع خاصیتها خودشان را نشان میدهند. پس به این نحو مقادیر، داخل کنترل هر تگ تعریف میشود ولی توسط پنل مورد استفاده قرار میگیرد. نحوهی نوشتن این نوع خاصیت: ابتدا یک پیشوند از نوع تگ پنل را در ابتدا آورده و سپس بعد از .(نقطه) نام خاصیت را ذکر میکنیم.
نحوهی تعریف این نوع خاصیتها در یک کلاس به صورت زیر است که برای شیء یا پنل canvas میباشد:
public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached("Top", typeof(double), typeof(Canvas), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.Inherits)); public static void SetTop(UIElement element, double value) { element.SetValue(TopProperty, value); } public static double GetTop(UIElement element) { return (double)element.GetValue(TopProperty); }
<Button Content="Dock=Top" DockPanel.Dock="Top"/> <Button Content="Dock=Bottom" DockPanel.Dock="Bottom"/> <Button Content="Dock=Left"/> <Button Content="Dock=Left2"/> <Button Content="Right2" DockPanel.Dock="Right"/> <Button Content="Dock=Right" DockPanel.Dock="Right"/> <Button Content="LastChildFill=True"/>
Wrap Panel
این پنل بسیار شبیه StackPanel هست ولی مثل آن اشیاء را در یک سطر یا ستون ادامه نمیدهد؛ بلکه با رسیدن به انتهای پنجره، سطر یا ستون جدیدی را آغاز میکند. در stack panel با پایان پنجره، ادامه اشیا آن قابل مشاهده نبود ولی در این شیء با اتمام و رسیدن به لبهی پنجره، اشیاء در سر جدید (افقی) یا ستون جدید (عمودی) نمایش داده میشوند. این پنلها میتوانند در ساخت تبها و نوار ابزار استفاده شوند.
Canvas Panel
پایهایترین layout موجود در WPF است. موقعیت قرارگیری المانهای فرزندش بر اساس نقاط تعیین شده است.این پنل بیشتر برای رسم اشکال و گرافیک دو بعدی مناسب است و اصلا برای قرارگیری کنترلهای WPF روی آن توصیه نمیشود و مشکل winformها در آن رخ خواهد داد.
شروع ترسیم یک شکل دو بعدی روی آن بر اساس دوتا از چهار "خاصیتهای وابستگی متصل" صورت میگیرد که به شرح زیر هستند:
- Canvas.LEFT
- Canvas.RIGHT
- Canvas.TOP
- Canvas.BOTTOM
نمونه از کد نوشته شده آن به صورت زیر است:
<Canvas> <Rectangle Canvas.Left="40" Canvas.Top="31" Width="63" Height="41" Fill="Blue" /> <Ellipse Canvas.Left="130" Canvas.Top="79" Width="58" Height="58" Fill="Blue" /> <Path Canvas.Left="61" Canvas.Top="28" Width="133" Height="98" Fill="Blue" Stretch="Fill" Data="M61,125 L193,28"/> </Canvas>
ترتیب قرارگیری اشکال روی هم در canvas به ترتیبی انجام میگیرد که در XAML نوشته اید ولی میتوان با استفاده از خاصیت Canvas.ZIndex این ترتیب را تغییر داد.
<Canvas> <Ellipse Fill="Green" Width="60" Height="60" Canvas.Left="30" Canvas.Top="20" Canvas.ZIndex="1"/> <Ellipse Fill="Blue" Width="60" Height="60" Canvas.Left="60" Canvas.Top="40"/> </Canvas>
ViewBox
نمونهی کد زیر را تست کنید تا تفاوت بین دو Button را ببینید:
<StackPanel Orientation="Vertical"> <Button Content="Test" /> <Viewbox Stretch="Uniform"> <Button Content="Test" /> </Viewbox> </StackPanel>
در بخش دوم Layoutها مبحث گرید و ساخت Layout اختصاصی و تعدادی از خاصیتها را بررسی خواهیم کرد.
در این بین راه حل دیگری نیز وجود دارد که با تمام مرورگرها سازگار است؛ اما تنها گزارش درصد آپلود را توسط آن نخواهیم داشت. در اینجا به صورت پویا یک IFrame مخفی در صفحه تشکیل میشود، مقادیر معمولی فرم (تمام المانها، منهای file) به صورت Ajax ایی به سرور ارسال خواهند شد. المان file آن در این IFrame مخفی، به صورت معمولی به سرور Postback میشود. البته کاربر در این بین چیزی را مشاهده یا احساس نخواهد کرد و تمام عملیات از دیدگاه او Ajax ایی به نظر میرسد. برای انجام اینکار تنها کافی است از افزونهی AjaxFileUpload استفاده کنیم که در ادامه نحوهی استفاده از آنرا بررسی خواهیم کرد.
پیشنیازها
در ادامه فرض بر این است که افزونهی AjaxFileUpload را دریافت کرده و به فایل Layout برنامه افزودهاید:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title - My ASP.NET Application</title> <link href="~/Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div> @RenderBody() </div> <script src="~/Scripts/jquery-1.11.1.min.js"></script> <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script> <script src="~/Scripts/ajaxfileupload.js"></script> @RenderSection("Scripts", required: false) </body> </html>
مدل، کنترلر و View برنامه
مدل برنامه مشخصات یک محصول است:
namespace MVCAjaxFormUpload.Models { public class Product { public int Id { set; get; } public string Name { set; get; } } }
کنترلر آن از سه متد تشکیل شدهاست:
using System.Threading; using System.Web; using System.Web.Mvc; using MVCAjaxFormUpload.Models; namespace MVCAjaxFormUpload.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(Product product) { var isAjax = this.Request.IsAjaxRequest(); return Json(new { result = "ok" }, JsonRequestBehavior.AllowGet); } [HttpPost] public ActionResult UploadFiles(HttpPostedFileBase image1, int id) { var isAjax = this.Request.IsAjaxRequest(); Thread.Sleep(3000); //شبیه سازی عملیات طولانی return Json(new { FileName = "/Uploads/filename.ext" }, "text/html", JsonRequestBehavior.AllowGet); } } }
Index دوم کار پردازش Ajax ایی اطلاعات ارسالی به سرور را به عهده دارد. HttpPost آن Ajax ایی است.
متد UploadFiles، کار پردازش اطلاعات ارسالی از طرف IFrame مخفی را انجام میدهد. HttpPost آن معمولی است.
و کدهای View این مثال نیز به شرح زیر است:
@model MVCAjaxFormUpload.Models.Product @{ ViewBag.Title = "Index"; } <h2>Ajax Form Upload</h2> @using (Ajax.BeginForm(actionName: "Index", controllerName: "Home", ajaxOptions: new AjaxOptions { HttpMethod = "POST" }, routeValues: null, htmlAttributes: new { id = "uploadForm" })) { <label>Name:</label> @Html.TextBoxFor(model => model.Name) <br /> <label>Image:</label> <br /> <input type="file" name="Image1" id="Image1" /> <br /> <input type="submit" value="Submit" /> <img id="loading" src="~/Content/Images/loading.gif" style="display:none;"> } @section Scripts { <script type="text/javascript"> $(function () { $('#uploadForm').submit(function () { $("#loading").show(); $.ajaxFileUpload({ url: "@Url.Action("UploadFiles", "Home")", // مسیری که باید فایل به آن ارسال شود secureuri: false, fileElementId: 'Image1', // آی دی المان ورودی فایل dataType: 'json', data: { id: 1, data: 'test' }, // اطلاعات اضافی در صورت نیاز success: function (data, status) { $("#loading").hide(); if (typeof (data.FileName) != 'undefined') { alert(data.FileName); } }, error: function (data, status, e) { $("#loading").hide(); alert(e); } }); }); }); </script> }
در ادامه نحوهی فعال سازی ajaxFileUpload را دقیقا در زمان submit فرم، مشاهده میکنید. در اینجا url آن به اکشن متدی که اطلاعات المان file را باید دریافت کند، اشاره میکند. fileElementId آن مساوی Id المان فایل فرم Ajax ایی صفحهاست. از قسمت data جهت ارسال اطلاعات اضافهتری به اکشن متد UploadFiles استفاده میشود. سایر قسمتهای آن نیز مشخص هستند. اگر عملیات موفقیت آمیز بود، success آن و اگر خیر، error آن اجرا میشوند.
فقط باید دقت داشت که content type دریافتی توسط آن باید text/html باشد، که این مورد در اکشن متدهای کنترلر مشخص هستند.
به این ترتیب دیگر کاربر نیازی ندارد ابتدا یکبار بر روی دکمهی دومی کلیک کرده و فایل را ارسال کند و سپس بار دیگر بر روی دکمهی submit فرم کلیک نماید. هر دو کار توسط یک دکمه انجام میشوند.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید
MVCAjaxFormUpload.zip
Url Routing در ASP.Net WebForms
نمونه آنرا در مطلب « پیاده سازی دکمه «بیشتر» یا «اسکرول نامحدود» به کمک jQuery در ASP.NET MVC » (کامنت آخر آن) پیاده سازی شده میتوانید مشاهده و دریافت کنید. از این قابلیت در سایت جاری در حال استفاده است. مثلا اگر به قسمت مطالب در بالای صفحه مراجعه کنید، چنین آدرسی قابل مشاهده است:
https://www.dntips.ir/postsarchive#/page/1/date/desc
در پایین صفحه اگر دراپ داونهای مرتب سازی را تغییر دهید، نام فیلد یا صعودی و نزولی بودن آدرس تغییر میکنند. شماره صفحه نیز با هر بار کلیک بر روی دکمهی بیشتر یکی اضافه میشود. همچنین این آدرسها را میشود ذخیره و عینا بازیابی کرد.