نظرات مطالب
چگونه نرم افزارهای تحت وب سریعتری داشته باشیم؟ قسمت سوم
1. اکثر کنترل‌های ASP.NET WebForm قابلیت bind به DataSet را دارد. اگر از آنها در این مدل استفاده نمایید کار صفحه بندی به عهده کنترل+DataSet می‌افتد.
2. صفحه بندی مجازی یعنی شما به کنترل می‌گویید کل اطلاعات شما مثلا 51 صفحه است، الان صفحه 4 را نمایش می‌دهی این هم اطلاعات صفحه 4. بعد وقتی کاربر بر روی گزینه صفحه بعد کلیک کرد، به کنترل می‌گویید کل اطلاعات 51 صفحه است، الان صفحه 5 را نمایش می‌دهی و این هم اطلاعات آن.
برای مثال می‌توانی به این مثال   در DataTables مراجعه کنید
مطالب
نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Popover به کمک Twitter bootstrap
این مطلب در ادامه بحث «اعمال کلاس‌های ویژه اعتبارسنجی Twitter bootstrap به فرم‌های ASP.NET MVC» می‌باشد. بنابراین تعاریف مدل و کنترلر آن، به همراه توضیحات ذکر شده در آن، در ادامه مورد استفاده قرار خواهند گرفت.


اصول نمایش Popover در Twitter bootstrap

PopOverها نیز یکی دیگر از کامپوننت‌های جاوا اسکریپتی مجموعه بوت استرپ هستند. بسیار شبیه به Tooltip بوده، اما ماندگارتر هستند. PopOverها با کلیک بر روی یک عنصر باز شده و تنها با کلیک مجدد بر روی آن المان، بسته می‌شوند (البته این موارد نیز قابل تنظیم هستند).
<a rel="popover" 
               data-content="محتوایی برای نمایش" 
               data-original-title="عنوان" href="#">اطلاعات</a>

    <script type="text/javascript">
        $(document).ready(function () {
            $("[rel='popover']").popover({ placement: 'left' })
                            .click(function (e) { e.preventDefault(); });
        });
   </script>
نحوه استفاده از آن را در مثال فوق مشاهده می‌کنید. در اینجا یک لینک با rel=popover تعریف شده است. از این rel، در یافتن کلیه المان‌هایی اینگونه، توسط jQuery استفاده خواهیم کرد. سپس مقدار ویژگی data-content، محتوای اطلاعاتی را که باید نمایش داده شود، مشخص می‌کند. همچنین برای مشخص ساختن عنوان آن می‌توان از ویژگی data-original-title استفاده کرد. نهایتا نیاز است افزونه popover بر روی المان‌هایی با rel=popover فراخوانی گردد. در روال رخدادگردان click آن، با استفاده از e.preventDefault، سبب خواهیم شد تا با کلیک بر روی لینک تعریف شده، صفحه مجددا بازیابی نشده و مکان اسکرول عمودی صفحه، تغییر نکند.


تبدیل خطاهای اعتبارسنجی ASP.NET MVC به PopOver

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

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


کدهای کامل View برنامه

@model Mvc4TwitterBootStrapTest.Models.User
@{
    ViewBag.Title = "Index";
}
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true, null, new { @class = "alert alert-error alert-block" })

    <fieldset class="form-horizontal">
        <legend>تعریف کاربر جدید</legend>
        <div class="control-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label" })
            <div class="controls">
                @Html.EditorFor(model => model.Name)
                @*@Html.ValidationMessageFor(model => model.Name, null, new { @class = "help-inline" })*@
            </div>
        </div>
        <div class="control-group">
            @Html.LabelFor(model => model.LastName, new { @class = "control-label" })
            <div class="controls">
                @Html.EditorFor(model => model.LastName)
                @*@Html.ValidationMessageFor(model => model.LastName, null, new { @class = "help-inline" })*@
            </div>
        </div>
        <div class="form-actions">
            <button type="submit" class="btn btn-primary">
                ارسال</button>
        </div>
    </fieldset>
}
@section JavaScript
{
    <script type="text/javascript">
        $.validator.setDefaults({
            showErrors: function (errorMap, errorList) {
                this.defaultShowErrors();
                //اگر المانی معتبر است نیاز به نمایش پاپ اور ندارد
                $("." + this.settings.validClass).popover("destroy");
                //افزودن پاپ اورها
                for (var i = 0; i < errorList.length; i++) {
                    var error = errorList[i];
                    $(error.element).popover({ placement: 'left' })
                                    .attr("data-original-title", "خطای اعتبارسنجی")
                                    .attr("data-content", error.message);
                }
            },
            // همانند قبل برای رنگی کردن کل ردیف در صورت عدم اعتبار سنجی و برعکس
            highlight: function (element, errorClass, validClass) {
                if (element.type === 'radio') {
                    this.findByName(element.name).addClass(errorClass).removeClass(validClass);
                } else {
                    $(element).addClass(errorClass).removeClass(validClass);
                    $(element).closest('.control-group').removeClass('success').addClass('error');
                }
                $(element).trigger('highlited');
            },
            unhighlight: function (element, errorClass, validClass) {
                if (element.type === 'radio') {
                    this.findByName(element.name).removeClass(errorClass).addClass(validClass);
                } else {
                    $(element).removeClass(errorClass).addClass(validClass);
                    $(element).closest('.control-group').removeClass('error').addClass('success');
                }
                $(element).trigger('unhighlited');
            }
        });
        //برای حالت پست بک از سرور عمل می‌کند
        $(function () {
            $('form').each(function () {
                $(this).find('div.control-group').each(function () {
                    if ($(this).find('span.field-validation-error').length > 0) {
                        $(this).addClass('error');
                    }
                });
            });
        });
   </script>
}
کدهای مدل و کنترلر، همانند مطلب «اعمال کلاس‌های ویژه اعتبارسنجی Twitter bootstrap به فرم‌های ASP.NET MVC» می‌باشند و از تکرار مجدد آن‌ها در اینجا صرفنظر گردید.

توضیحات
- با توجه به اینکه دیگر نمی‌خواهیم خطاها به صورت برچسب در مقابل کنترل‌ها نمایش داده شوند، کلیه Html.ValidationMessageFor به صورت کامنت درآورده شده‌اند.
- تغییر دوم مطلب جاری، اضافه شدن متد showErrors به تنظیمات پیش فرض jQuery Validator است. در این متد، اگر المانی معتبر بود، Popover آن حذف می‌شود یا در سایر حالات، المان‌هایی که نیاز به اعتبارسنجی سمت کلاینت دارند، یافت شده و سپس ویژگی data-content با مقداری معادل خطای اعتبارسنجی متناظر، به این المان افزوده و سپس متد popover بوت استرپ بر روی آن فراخوانی می‌گردد.
به عبارتی زمانیکه یک input box در ASP.NET MVC به همراه مقادیر مرتبط با اعتبارسنجی آن رندر می‌شود، چنین شکلی را خواهد داشت:
<input class="text-box single-line" data-val="true" data-val-required="لطفا نام را تکمیل کنید"
 id="Name" name="Name" type="text" value="" />
اما در اینجا به صورت پویا، data-original-title و data-content نیز به آن افزوده می‌گردند:
<input class="text-box single-line input-validation-error" data-val="true" data-val-required="لطفا نام را تکمیل کنید"
 id="Name" name="Name" type="text" value="" 
data-original-title="خطای اعتبارسنجی" title="" data-content="لطفا نام را تکمیل کنید">
این مقادیر توسط افزونه popover بوت استرپ شناسایی شده و مورد استفاده قرار می‌گیرد.
البته این موارد را در صورت نیاز به صورت دستی نیز می‌توان تعریف و اضافه کرد:
 @Html.TextBoxFor(x => x.Name, 
         new { data_content = "Name is required", 
               data_original_title = "Error", rel="popover" })
مطالب
Pipeها در Angular 2 – قسمت دوم – ساخت Pipe سفارشی
در قسمت قبل، مقدماتی از Pipeها را مورد برسی قرار دادیم؛ از جمله کاربرد Pipeها، نحوه استفاده از آنها، معرفی یکسری Pipe از پیش ساخته شده Angular، نحوه ارسال پارامتر به آنها و همچنین نحوه استفاده از آنها را در داخل Typescript، فراگرفتیم. در این قسمت نحوه ساخت Pipeهای سفارشی و همچنین نکات تکمیلی در مورد آنها را مورد بحث و بررسی قرار می‌دهیم.

نحوه ساخت Pipe سفارشی

علاوه بر استفاده از Pipeهای از پیش ساخته شده Angular، شما می‌توانید Pipeهای سفارشی خود را نیز تعریف و استفاده کنید. به عنوان مثال می‌خواهیم Pipe ای را با نام perNumber تعریف کنیم، تا تمامی اعداد موجود در عبارت ورودی Pipe را به صورت اعداد فارسی نمایش دهد. یعنی با اعمال این Pipe به عدد 123456 خروجی ۱۲۳۴۵۶ مورد انتظار است. برای ایجاد Pipe سفارشی مراحل زیر را انجام دهید.


قدم اول - ساخت یک فایل با نام دلخواه

طبق Style Guide در Angular.io نام این فایل را per-number.pipe.ts انتخاب می‌کنیم.


قدم دوم – افزودن ماژولهای مورد نیاز

داخل فایل ایجاد شده ماژول‌های Pipe و PipeTransform را با استفاده از دستور import از angular/core@ اضافه می‌کنیم.
 import { Pipe, PipeTransform } from '@angular/core';


قدم سوم – ساخت کلاس و مزین کردن آن به Pipe@

یک کلاس با نام دلخواه را مثلا به نام PerNumberPipe ایجاد می‌کنیم. این کلاس علاوه بر اینکه PipeTransform را پیاده سازی خواهد کرد، مزین به متادیتای Pipe@ نیز می‌باشد. متادیتای Pipe@ هنگام تزئین کلاس، یک نام را دریافت می‌کند. این نام قرار است به عنوان نام نهایی Pipe برای اعمال بر روی Template expressions مورد استفاده قرار بگیرد.
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'perNumber'}) export class PerNumberPipe implements PipeTransform {

}


قدم چهارم – پیاده سازی متد transform

به واسطه اعمال اینترفیس PipeTransform، این کلاس باید متد transform را پیاده سازی کند. این متد در پارامتر اول خود، عبارت ورودی را که قرار است Pipe بر روی آن اعمال شود، دریافت می‌کند و در ادامه تعداد دلخواهی پارامتر ورودی Pipe را که می‌خواهد، می‌تواند دریافت کند.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'perNumber'})
export class PerNumberPipe implements PipeTransform {
    transform(value: any, ...args: any[]): any {

    }
}

نکته ۱: نام انتخابی برای Pipe در آذین‌گر Pipe@ بایستی یک شناسه معتبر در JavaScript باشد.
نکته ۲: متد transform برای Pipe اجباری است و حتما بایستی پیاده سازی شود. اینترفیس PipeTransform این متد را برای کلاس اجباری می‌کند؛ هرچند استفاده از این اینترفیس برای کلاس Pipe کاملا اختیاری است.


قدم آخر – نوشتن کد تبدیل اعداد

Pipe مورد نظر ما قرار است یک رشته عددی را از ورودی دریافت کند و تمامی اعداد لاتین آن را به فارسی تبدیل کند. همچنین این Pipe هیچگونه پارامتری را دریافت نمی‌کند. کد زیر نحوه پیاده سازی متد transform را نمایش می‌دهد.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'perNumber'}) export class PerNumberPipe implements PipeTransform {
    transform(input: string): string{
        if (input == undefined) return '';
        var str = input.toString().trim();
        if (str === "") return "";
        str = str.replace(/0/g, '۰');
        str = str.replace(/1/g, '۱');
        str = str.replace(/2/g, '۲');
        str = str.replace(/3/g, '۳');
        str = str.replace(/4/g, '۴');
        str = str.replace(/5/g, '۵');
        str = str.replace(/6/g, '۶');
        str = str.replace(/7/g, '۷');
        str = str.replace(/8/g, '۸');
        str = str.replace(/9/g, '۹');
        return str;
    }
}


نحوه معرفی Pipe سفارشی به برنامه

حالا جهت استفاده از Pipe سفارشی در کامپوننت‌های خود کافی است آنرا یکبار در قسمت declarations در AppModule خود  تعریف کنید.
import { PerNumberPipe } from './pipes/per-number.pipe.ts'
...

declarations: [PerNumberPipe]


نحوه استفاده از Pipeهای سفارشی 

نحوه استفاده از Pipeهای سفارشی، دقیقا مشابه Pipeهای از قبل ساخته شده Angular می‌باشد.
<h3>{{'12345679' | perNumber}}</h3>
 

یکسری از Pipeهای مربوط به زبان فارسی در گیت‌هاب بنده پیاده سازی شده است که نیازمند همکاری دوستان است. لطفا جهت همکاری برای ساخت یک ابزار جامع برای زبان فارسی در Angular به این لینک مراجعه کنید.
 
Pipeها و تشخیص تغییرات

Angular برای اعمال Pipe بر روی Template expressions بایستی تمامی رخدادهای برنامه را تحت نظر قرار داده و با مشاهده هر تغییری بر روی عبارت ورودی Pipe، فراخوانی Pipe را آغاز کند. از جمله این رخدادها می‌توان به رخداد mouse move، timer tick، server response و فشرده شدن کلیدهای ماوس و یا کیبورد اشاره کرد. واضح است که بررسی تغییرات عبارت در این همه رخداد می‌تواند مخرب باشد و بر روی کارآئی (Performance) تاثیر منفی خواهد گذاشت. اما Angular برای حل این مشکل و همچنین هنگام مشاهده سریع تغییرات هنگام استفاده از Pipeها، الگوریتم‌های سریع و ساده‌ای در نظر گرفته است.


در قسمت بعد با انواع Pipeها در Angular و همچنین نحوه پیاده سازی آنها، آشنا خواهیم شد. 
مطالب
تغییرات بوجود آمده در Bundling and Minification -MVC4
همانطور که در پست قبلی اشاره کردم نسخه جدید MVC با تغییرات جهت بهبود کاربری همراه بوده است.
در این پست قصد دارم شما رو با ویژگی جدید  Bundling and Minification بر روی فایلهای  Css و JavaScript آشنا کنم.اگر یک پروژه جدید به وسیله MVC 4 ابجاد کنید شاهد تغییراتی بر روی فایلهای _Layout.cshtml and Global.asax.cs خواهید بود.این تغییر شامل اضافه شدن System.Web.Optimization and BundleTable.Bundles به  Layout.cshtml است.
<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")"rel="stylesheet" type="text/css" />

<link href="@System.Web.Optimization.BundleTable. Bundles.ResolveBundleUrl("~/Content/themes/base/css")" rel="stylesheet" type="text/css" />

<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script> 
که این Reference ها به عنوان Html Helper ساده هستند.
اگر به کدهای HTML  مرورگر خود نگاه کنید شاهد کدهای زیر خواهید بود.
 <link href="/Content/css?v=ji3nO1pdg6VLv3CVUWntxgZNf1z" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/css?v=UM624qf1uFt8dYti" rel="stylesheet" type="text/css" />
<script src="/Scripts/js?v=4h5lPNUsLiFoa0vqrItjS2Jp"></script>
که این به معنی فشرده شدن و همچنین باعث میشود اطلاعات ارسالی از IIS Web Server کمتر باشد.
برای استفاده از این ویژگی می‌بایست در Global.asax.cs  در قسمت  Application Startup متد زیر را اضافه کنیم.
BundleTable.Bundles.RegisterTemplateBundles();
برای ساختن Bundle سفارشی به صورت extension method  به صورت زیر عمل میکنیم.
public static void EnableBootstrapBundle(this BundleCollection bundles) {
      var bootstrapCss = new Bundle("~/bootstrap/css", new CssMinify());
      bootstrapCss.AddFile("~/css/bootstrap.css");
      bootstrapCss.AddFile("~/css/bootstrap-responsive.css");
      bootstrapCss.AddFile("~/css/application.css");
      bootstrapCss.AddFile("~/css/prettify.css");

      bundles.Add(bootstrapCss);

      var bootstrapJs = new Bundle("~/bootstrap/js", new JsMinify());
      bootstrapJs.AddFile("~/js/jquery-1.7.1.js");
      bootstrapJs.AddFile("~/js/bootstrap.js");
      bootstrapJs.AddFile("~/js/prettify.js");

      bundles.Add(bootstrapJs);
}
 در مثال بالا CssMinify وJsMinify برای مشخص شدن نوع فشرده سازی ما استفاده شده است.
برای استفاده از این ویژگی می‌بایست در Global.asax.cs  در قسمت  Application Startup متد زیر را اضافه کنیم.
BundleTable.Bundles.EnableBootstrapBundle();
و در فایل Layout.cshtm همانند مثال قبلی کد زیر را اضافه میکنیم.
<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bootstrap/css")" rel="stylesheet">
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bootstrap/js")"></script>
و اگر دوباره به کد تولیدی در مرورگر نگاهی بیاندازیم:
<link href="/bootstrap/css?v=uBlJsuIAGAF93nUTTez8" rel="stylesheet">
<script src="/bootstrap/js?v=O6HaHC8QqtB"></script>
.میتونه تنها ایرادش باشه   CDN عدم پشتیبانی از 
.البت شاید من نتونستم راهی براش پیدا کنم
کار اضافه ای قرار نیست انجام دهیم همه اینها به صورت توکار اعمال میشوند. 
 به طور خلاصه میشه گفت ویژگی بالا به بهبود عملکرد برنامه شما کمک زیادی میکنه.
مطالب
انتخاب layoutهای متفاوت در برنامه‌های Angular
شاید برای شما هم پیش آمده باشد که در یک برنامه‌ی Angular بخواهید layoutهای مختلفی داشته باشید؛ مثلا هنگام لاگین، طبق عرف کار باید هدر و فوتر صفحه از بین بروند و فقط فرم لاگین نمایش داده شود و یا بخواهید هنگام لاگین، یک layout مخصوص پنل مدیریتی داشته باشید و یا …

قبل از شروع، فرض را بر آن می‌گیریم که حداقل نیاز‌های یک پروژه‌ی Angular را آماده کرده اید. سپس یک پوشه‌ی جدید را به نام layout می‌سازیم و layout‌های مربوطه را در آن ایجاد میکنیم. با دستور زیر یک کامپوننت جدید را که layout ما خواهد شد، با نام دلخواهی ایجاد می‌کنیم:
ng g c Loginlayout
 و همچنین یک کامپوننت دیگر را برای صفحه‌ی اصلی به نام homelayout می‌سازیم:
ng g c homelayout

در ادامه Loginlayout را باز کرده و تنظیمات زیر را لحاظ کنید:
<div style="width: 100%;height: 250px;background-color: aquamarine">
   <h1>Header</h1>
</div>

<router-outlet></router-outlet>

<div style="width: 100%;height: 250px;background-color: brown">
  <h1>Foother</h1>
</div>
در اینجا یک هدر و یک فوتر را ساخته و <router-outlet></router-outlet> را در آن قرار می‌دهیم که قسمت پویای ما خواهد شد.

اکنون وارد کامپوننت home layout شوید و دقیقا مانند قبل، تنظیمات دلخواه خود را انجام داده و همچنین <router-outlet></router-outlet> راهم درون جائیکه می‌خواهید به صورت پویا باشد بگذارید.
تا اینجا ما فقط layoutها را طراحی کردیم. در ادامه در ریشه‌ی پروژه، سه کامپوننت را به نام‌های Home , Login, About میسازیم. Home و About دارای یک قالب و Login هم داری قالب مخصوص به خود میباشد.

سپس وارد کامپوننت آغازین برنامه (app.component.html) شوید و در آن <router-outlet></router-outlet> را وارد کنید. در اینجا دیگر نیازی به نوشتن تگ‌های خاص دیگری نیست.

در ادامه به اصلی‌ترین قسمت، یعنی مسیریابی می‌رسیم. وارد app.module.ts شوید و آن را به صورت زیر تنظیم کنید:
export const routes: Routes = [    
           { 
                path: 'Loginlayout', 
                component: LoginlayoutComponent ,
                children: [
                  { path: 'Login', component: LoginComponent, pathMatch: 'full'}                 
                ]
            },
            { 
                path: 'Homelayout', 
                component: HomelayoutComponent,
                children: [
                  { path: 'About', component: AbouComponent, pathMatch: 'full'},
                  { path: 'Home', component: HomeComponent, pathMatch: 'full'}
                ]
            }          
];
همانطورکه ملاحظه می‌کنید، مسیریابی بالا شامل مسیریابی‌های تو در تویی است. در اینجا کامپوننت‌های Home و About درون HomelayoutComponent بارگذاری می‌شوند و خود HomelayoutComponent  نیز درون app.component.
همچنین برای اینکه مشخص شود کدام کامپوننت به عنوان کامپوننت پیشفرض نمایش داده شود، به صورت زیر عمل میکنیم:
path: '', 
component: HomelayoutComponent,
children: [
  { path: '', component:HomeComponent, pathMatch: 'full'}         
]
به  این روش میتوانید هر تعداد layout ایی را که میخواهید، ایجاد کنید.

کدهای کامل این مطلب را می‌توانید از اینجا دریافت و یا به صورت آنی آزمایش کنید.
مطالب
نمایش در حال بارگذاری بودن صفحه در برنامه‌های Angular
پیشتر در مورد HTTP Client جدید Angular، مطلب «ارتقاء به HTTP Client در Angular 4.3» را بررسی کردیم. یکی دیگر از قابلیت‌های HttpClient که روش اصلی دسترسی به اطلاعات از راه دور در Angular 5 نیز می‌باشد، امکان تعریف Interceptors سفارشی برای آن است. به کمک Interceptors می‌توان به تمامی درخواست‌های HTTP ارسالی و پاسخ‌های دریافتی از سرور گوش فرا داد و در این بین منطق ویژه‌ای را پیاده سازی کرد؛ مانندcaching ،logging و غیره. در مطلب جاری قصد داریم از این قابلیت برای نمایش یک loading bar مشخص کننده‌ی شروع و پایان تمامی درخواست‌های HTTP استفاده کنیم.


دریافت و نصب پیشنیازها

برای نمایش loading bar در بالای صفحه، از کامپوننت ng2-slim-loading-bar استفاده خواهیم کرد. دمویی از آن‌را در اینجا می‌توانید مشاهده کنید.
برای نصب آن، ابتدا دستور ذیل را در ریشه‌ی پروژه اجرا کنید:
 npm install ng2-slim-loading-bar --save
پس از آن فایل angular-cli.json. را گشوده و فایل css آن‌را تعریف نمائید:
"styles": [
   "../node_modules/ng2-slim-loading-bar/style.css",
   "styles.css"
],
در ادامه به فایل app.module.ts مراجعه کرد و ماژول آن‌را نیز به نحو ذیل به برنامه معرفی کنید:
import {SlimLoadingBarModule} from 'ng2-slim-loading-bar';

@NgModule({
imports: [
     //...
     SlimLoadingBarModule.forRoot()
  ]
})
export class AppModule {
}

پس از این مقدمات، هرجایی که نیاز به استفاده‌ی از آن با کدنویسی باشد، ابتدا سرویس SlimLoadingBarService آن‌را به سازنده‌ی کلاس کامپوننت مدنظر تزریق می‌کنیم و سپس از متدهای start ،stop و complete آن می‌توان استفاده کرد.
 import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
همچنین برای نمایش این کامپوننت باید selector آن را در فایل app.component.html در بالای صفحه اضافه کرد:
  <ng2-slim-loading-bar></ng2-slim-loading-bar>


تدارک یک LoaderInterceptor برای استفاده از ng2-slim-loading-bar

در ادامه می‌خواهیم هر زمانیکه در سراسر برنامه، درخواست HTTP ایی شروع شد، این کامپوننت نمایش داده شود و در پایان درخواست و یا درصورت بروز خطایی، پایان یابد و مخفی شود. برای این منظور یک Interceptor جدید را به صورت ذیل به پوشه‌ی Core برنامه اضافه می‌کنیم:
 ng g s core/interceptors/LoaderInterceptor --spec false
با این کدها:
import { Injectable } from "@angular/core";
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/do";
import { SlimLoadingBarService } from "ng2-slim-loading-bar";


@Injectable()
export class LoaderInterceptorService implements HttpInterceptor {

  constructor(private loadingBar: SlimLoadingBarService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // start our loader here
    this.loadingBar.start();
    return next.handle(req).do(
      (event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          this.loadingBar.complete();
        }
      },
      (err: any) => {
        this.loadingBar.complete();
      });
  }
}
توضیحات:
- برای پیاده سازی یک interceptor جدید، نیاز است کلاس سرویسی را که HttpInterceptor را پیاده سازی می‌کند، ایجاد کنیم. برای تکمیل این پیاده سازی نیاز است متد intercept را با امضایی که مشاهده می‌کنید، تعریف کنیم:
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- در اینجا پارامتر req به خود درخواست Http اشاره می‌کند.
- کار پارامتر next تنظیم و بازگشت یک HttpEvent observable توسط متد handle آن است.

برای نمونه در اینجا ابتدا سرویس SlimLoadingBarService به سازنده‌ی کلاس interceptor‌  تزریق شده‌است. سپس توسط آن می‌توان به متدهای start و complete این کامپوننت دسترسی یافت. برای مثال در ابتدای کار گوش فرادادن به درخواست جاری، متد start فراخوانی شده‌است و سپس زمانیکه پاسخی از سرور دریافت شده و یا خطایی رخ‌داده، متد complete آن فراخوانی شده‌است.


ثبت و معرفی LoaderInterceptorService به سیستم

برای معرفی interceptor تهیه شده، به فایل app.module.ts مراجعه کرد و قسمت providers آن‌را به نحو ذیل تکمیل می‌کنیم: 
 @NgModule({
  providers: [
   { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptorService, multi: true }
  ]
})
export class AppModule {}


آزمایش برنامه

اکنون اگر قسمت‌های مختلف برنامه را که با HttpClient جدید کار می‌کنند بررسی کنید، متوجه خواهید شد که با شروع هر درخواست، loading bar قرمزی در بالای صفحه ظاهر می‌شود و در پایان درخواست، به صورت خودکار مخفی می‌گردد. نکته‌ی مهم این روش عدم نیاز به تغییری در قسمت‌های مختلف برنامه است. این interceptor سراسری است و به صورت یکسانی بر روی کل برنامه تاثیر می‌گذارد.
نظرات مطالب
مبانی TypeScript؛ ماژول‌ها
درود جناب نصیری ، من یک مشکلی که دارم و الان یک ساعته که دارم R&D میکنم و موفق به حلش نشدم متاسفانه این هست که یک فایل جدید ts درست در روت پروژه درست کردم ( کلا پروزه شامل دو فایل app.ts و testmd.ts هست ) فایل testmd  یک کلاس رو تعریف کرده و اون رو export کرده و در  app اون رو import کردم و سعی دارم از اون کلاس استفاده کنم و درواقع خواستم این مطلب رو تست کنم و یک ماژول آزمایشی درست کنم و ازش استفاده کنم . هر کاری کردم پروژه بیلد نمیشه و خطای  Error TS2307 Cannot find module 'testmd'  در تب Error نمایش داده میشه . هر چی هم جستجو کردم به نتیجه ای نرسیدم واقعا. 
فایل پروژه هم اتچ کردم ، اگر ممکنه راهنمایی کنید خیلی ممنون میشم . 
محیط توسعه :
+ Visual Studio 2015 Update 2
+ آخرین نگارش Resharper که متناسب با نسخه TypeScript که 1.8 هست تنظیمش کردم ( چک کردم و نسخه‌های دیگه TypeScript  رو نصب ندارم)
+ Web Essentials 2015.3 v3.0.230 ، Web Extension Pack v1.4.44 ، Web Analyzer v1.7.77 
با تشکر 
مطالب
مقیدسازی (DataBinding) در WPF زمانی که دسترسی به DataContext وجود ندارد

در WPF و Silverlight می‌توان با استفاده از مقید سازی (DataBindingکنترل‌ها را به منبع‌های داده متصل کرد. این منابع به چند شیوه مختلف مانند استفاده مستقیم از خصوصیتSource  قابل دسترسی هستند. یکی از این روش ها، ارث بری از DataContext نزدیک‌ترین والد است.

همانطور که گفته شدDataContext  هر کنترل، توسط تمامی فرزندان آن قابل دسترسی است. اما در بعضی مواقع، زمانیکه کنترل فرزند، بخشی از visual یا logical tree نباشند، دسترسی به DataContext وجود ندارد.

برای مثال زمانی که نیاز است خصوصیت ItemsSource مربوط به یک به لیستی خارج از ItemsSource کنترل DataGrid DataGridTemplateColumn مثلا به لیستی درون ViewModel  مربوط به Window در مثال زیر مقید شود، به صورت معمول باید به این صورت عمل کرد:

ViewModel :

public List<People> ComboBoxDataSource{get; set;}

  : XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        x:Name="this">
    <Grid>
        <DataGrid ItemsSource="{Binding DataCollection}">
            <DataGrid.Columns>
                <DataGridComboBoxColumn ItemsSource="{Binding DataContext.ComboBoxDataSource, ElementName=this}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

با اینکه همه چیز درست به نظر می‌رسد اما در عمل هیچ اتصالی صورت نمی‌گیرد و در پنجره Output ویژوال استادیو خطای زیر مشاهده می‌شود:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element.
BindingExpression:Path=ComboBoxDataSource; DataItem=null; 
target element is 'DataGridComboBoxColumn' (HashCode=17334644); target property is 'ItemsSource' (type 'IEnumerable')

این خطا مشخص میکند که WPF نمیتواند تشخیص بدهد که کدام FrameWorkElement قرار است از DataContext استفاده کند؛ چرا که همانطور که قبلا عنوان شد DataGridTemplateColumn بخشی از visual  یا  logical treeنیست.

برای مشکل فوق در صورتیکه خصوصیت مورد نظر، یک خصوصیت از فرزندان کنترل باشد، از طریق استایل‌ها می‌توان مشکل را حل کرد. برای مثال به جای ItemSource مربوط به DataGridComboBoxColumn می‌توان خصوصیت ItemSource کنترل ComboBox درون آن را تنظیم کرد.

  <DataGridComboBoxColumn DisplayMemberPath="FirstName">
        <DataGridComboBoxColumn.EditingElementStyle>
              <Style TargetType="ComboBox">
                     <Setter Property="ItemsSource" Value="{Binding DataContext.ComboBoxDataSource , ElementName=this}"/>
               </Style>
         </DataGridComboBoxColumn.EditingElementStyle>
   </DataGridComboBoxColumn>

اما در صورتیکه نیاز باشد یک خصوصیت از خود DataGridComboBoxColumn مانند Visibility  مقید سازی شود، روش بالا کارساز نخواهد بود. برای حل مشکل فوق میتوان از کلاس‌های Freezable استفاده کرد؛ چرا که این کلاسها می‌توانند از DataContext ارث بری کنند حتی زمانیکه بخشی از visual یاlogical tree  نباشند. برای این کار می‌توان کلاس زیر را ایجاد کرد:

 public class DataBindingHelper : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new DataBindingHelper();
        }
        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(DataBindingHelper), new UIPropertyMetadata(null));
    }
و یک نمونه از آن را در Resource‌های DataGrid ساخت:

<DataGrid.Resources>
       <local:DataBindingHelper x:Key="bindingHelper"Data="{Binding}"/>
</DataGrid.Resources>

و هنگام مقید سازی خصوصیت Visibility مربوط به DataGridComboBoxColumn، از نمونه ساخته شده به عنوان  Source استفاده نمود.

<DataGridComboBoxColumn Visibility="{Binding Data.IsVisible,Converter={StaticResource visibilityConverter},Source={StaticResource bindingHelper}}"/>

مطالب
دو تنظیم ضروری VS.NET جهت کار با WPF و Silverlight

تنظیم اول: تغییر نحوه‌ی نمایش پیش فرض فایل‌های XAML

اگر فایل XAML شما اندکی حجیم شود نمایش آن در VS.NET کمی طولانی خواهد شد و حالت پیش فرض نمایش در VS.NET هم split view mode است (نمایش XAML و پیش نمایش آن با هم). این مورد هم پس از مدتی تبدیل به عذاب می‌شود. برای رفع آن می‌توان حالت پیش فرض نمایش یک فایل XAML را به XAML View تنها تغییر داد.
برای این منظور به منوی Tools ، گزینه‌ی Options و سپس قسمت تنظیمات Text editor مراجعه کنید. در اینجا در قسمت XAML ، گزینه‌ی Miscellaneous را انتخاب کرده و سپس "Always open documents in full XAML view" را تیک بزنید.



حتی ممکن است این مورد هم رضایت بخش نباشد. در این حالت می‌توان ویرایشگر پیش فرض را کلا تغییر داد. Design tab را در پایین صفحه از دست می‌دهیم اما هنوز intellisense کار می‌کند و اگر نیاز به designer بود فقط کافی است کلیک راست کرده و گزینه‌ی View designer را انتخاب کرد:
روی یک فایل XAML دلخواه کلیک راست کرده و گزینه‌ی Open with را انتخاب کنید. سپس "Source Code (Text) Editor" را انتخاب کرده و روی دکمه‌ی Set as Default کلیک کنید. تمام!
هر چند Blend این مشکلات را ندارد و با فایل‌های حجیم XAML به خوبی کاری می‌کند.


تنظیم دوم: تغییر نحوه‌ی نمایش مشکلات ناشی از Binding

عموما اگر مشکلاتی در حین عملیات Binding در WPF یا Silverlight وجود داشته باشند، خطاها در Debugger Output Window نمایش داده می‌شوند. حالت پیش فرض هم فقط روی Error تنظیم شده است به این معنا که warning ها را مشاهده نخواهید کرد. برای تغییر این مورد باید به صورت زیر عمل کرد:
به منوی Tools ، گزینه‌ی Options و سپس قسمت تنظیمات Debugging مراجعه کنید. گزینه‌ی Output Window -> WPF Trace Settings را انتخاب نمائید. سپس در اینجا قسمت WPF trace settings را یافته و مقدار پیش فرض Data binding را که به Error تنظیم شده است، به Warning تنظیم نمائید.