Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

IML TODO

Anna | 17.06.2014 | нет комментариев
disclaimer: статья является результатом на критику (которая обрушилась на прогре), раскрывая потенциал IML на примере знаменитого приложения ToDo MVC.

Получил тумаков


Критика – это слово весьма мягкое по отношению к дискуссии, которая появилась к моей предыдущей статье, потому что это было огромнее схоже на избиение в котором были весьма не славные комментарии (на фото топ абсурдных), но также и непредвзятые:

  • Код на AngularJs не фонтан — трудно опровергнуть, правда все они были с официального сайта и знаменитого начальства
  • Слабые примеры – упор был на задачи, а не на сценарии, но соглашусь что больше комплексное решение больше полно раскрывает потенциал (я предложил некоторые наши планы, которые открыты на open source, но они остались без внимания)
  • Не знаешь AngularJs? – по внятным причинам это дюже крепко задело разработчиков AngularJs
  • Топик JS – это серьезная оплошность, потому что не применяя asp.net mvc, трудно осознать прелести типизированных TextBoxFor и других растяжений.

Отчего ToDo?

В комментариях предложили испробовать реализовать “Todo MVC” в качестве доказательства вероятностей IML и теперь мы посмотрим что из этого получилось. Во первых demo версия, которая имеет одно отличите от тех, что представлены для js framework, в том, что в качестве хранилища применяется не local storage, а база данных, а также начальный код, тот, что мы будем разбирать дальше в посте. В процессе реализации я строил всю логику (расчеты подвала, скрытие элементов и т.д.) на заказчике, правда на реальных задачах, проще (изредка нужно) обновлять “точечно” элементы, которые имея IML код, знают, как себя вычислить и отобразить.

Code review

Жанр повествования в данный раз будет не сопоставление одного решения с иным (напротив объем материала будет огромным), а обзор кода, тот, что получится при реализации приложения todo. Я упоминал выше о том, что в реализации IML присутствует и серверная часть, но в целях уравнивания решаемых задач для больше объективного сопоставления, сфокусируемся только на клиентской части.

Из чего состоит

Код был поделен на 3 View

  • Index — основная страница ( и по факту исключительная для браузера )
  • Todo_List_Tmpl – образец для построения центрального списка
  • Todo_Footer_Tmpl – образец для построения подвала с показателями

image

Index ( состоит из 3 элементов )
Форма для добавления TODO
@using (Html.When(JqueryBind.Submit)
            .DoWithPreventDefault()
            .Submit(options =>
                   {
       options.Url = Url.Dispatcher()
                     .Push(new AddTodoCommand {  ClientId = Selector.Incoding.Cookie(CookieManager.ClientId) });
                   })
            .OnSuccess(dsl =>
                           {
                               dsl.WithId(containerId).Core().Trigger.Incoding();
                               dsl.Self().Core().Form.Reset();
                           })
            .AsHtmlAttributes()
            .ToBeginTag(Html, HtmlTag.Form))
{
    @Html.TextBoxFor(r => r.Title, new { placeholder = "What needs to be done?", autofocus = "" })
}

примечание: сразу жду фразы в жанре “Да, ну это не серьезно, кода в разы огромнее, нужно всюду копировать, посмотри как люди делают !!!” — на что у меня есть довод в лице C# extensions, тот, что разрешает оборачивать конструкции IML. Дальше в статье будет приведены альтернативные варианты решения задач (также repository на GibHub с переработанным кодом) с использованием C# extensions 

Что к чему?
  • When(JqueryBind.Submit) — указываем целевое событие
  • DoWithPreventDefault — поведение события ( отменяем обработчик браузера )
  • Submit — отправляем форму через ajax
    примечание: пару примечаний по представленной реализации:

    • Url куда отправляется форма задается в опциях (а не через признак action у form)
    • ClientId дозволено перенести форму, как Hidden, тот, что по InitIncoding проставит значение из Cookies, что бы вызывать Submit без параметров
  • OnSuccess — исполняем позже благополучного заключения submit
    • Trigger Incoding to containerId – запускаем каждый IML код для элемента Container (изложение ниже)
      примечание: дозволено использовать больше одного When, что разрешает подвязаться на различные события (с различным IML кодом), следственно trigger Incoding запускает все цепочки.
    • Form reset – сбрасываем значение элементов формы
  • AsHtmlAttributes — собираем IML код в комфортный для asp.net mvc формат (RouteValueDictionary)
  • ToBeginTag — упаковываем полученные признаки в тэг form (правило работы как Html.BeginForm)
    примечание: дозволено применятьHtml.BeginForm(“action”,”controller”,Post,iml.AsHtmlAttributes())
Форма для добавления TODO (альтернативный вариант)
@using (Html.Todo().BeginForm(setting =>
                             {
                    setting.TargetId = containerId;
                    setting.Routes = new { ClientId = Selector.Incoding.Cookie(CookieManager.ClientId) };
                             }))
{
    @Html.TextBoxFor(r => r.Title, new { placeholder = "What needs to be done?", autofocus = "" })
}

примечание: кода стало поменьше и что самое основное, сейчас дозволено расширять (валидация, redirect позже submit и т.д.) способ, под нужды определенного плана.

Под капотом

public class BeginFormSetting
{
    public string TargetId { get; set; }

    public object Routes { get; set; }
}

public BeginTag BeginForm(Action configure)
{
    var setting = new BeginFormSetting();
    configure(setting);

    var url = new UrlHelper(HttpContext.Current.Request.RequestContext);
    return this.helper.When(JqueryBind.Submit)
               .DoWithPreventDefault()
               .Submit(options =>
                           {
                               options.Url = url.Dispatcher()
                                                .Push(setting.Routes);
                           })
               .OnSuccess(dsl =>
                              {
                                  dsl.WithId(setting.TargetId).Core().Trigger.Incoding();
                                  dsl.Self().Core().Form.Reset();
                              })
               .AsHtmlAttributes()
               .ToBeginTag(this.helper, HtmlTag.Form);
}

примечание: код знаком большинству asp.net mvc разработчиков, но стоит подметить то, что взамен “обычных” параметров, мы передаем неизвестный способ, тот, что принимает класс настроек.

Container
@(Html.When(JqueryBind.InitIncoding | JqueryBind.IncChangeUrl)
      .Do()
      .AjaxGet(Url.Dispatcher()
                  .Query(new
                         {
                   ClientId = Selector.Incoding.Cookie(CookieManager.ClientId),
                   Type = Selector.Incoding.HashQueryString(r => r.Type)
                         })
                  .AsJson())
      .OnSuccess(dsl =>
                     {
                         string urlTmpl = Url.Dispatcher()
                                             .Model(new GetTodoByClientQuery.Tmpl { FooterId = footerId })
                                             .AsView("~/Views/Home/Todo_List_Tmpl.cshtml");
                         dsl.Self().Core().Insert.WithTemplateByUrl(urlTmpl).Html();
                         dsl.WithId(footerId).Core().Trigger.Incoding();
                     })
      .AsHtmlAttributes(new { id = containerId })
      .ToDiv())
Что к чему?
  • When(JqueryBind.InitIncoding | IncChangeUrl) — указываем целевые события
    • InitIncoding – срабатывает при первом возникновении элемента на странице (не значимо ajax либо традиционно)
    • IncChangeUrl – срабатывает при метаморфоза hash
  • Do — поведение события
  • AjaxGet — указываем url, на тот, что будет исполнен ajax запрос
    • ClientId – получаем значение изcookies
    • Type – получаем значение из Hash Query String
  • OnSuccess — исполняем позже благополучного заключения AjaxGet
    • Insert data to self by template – вставляем полученные данные из запроса ( json ) через template ( Todo_List_Tmpl ниже ) в нынешний элемент.
      примечание: template дозволено получить через всякий доступный Selector, скажем прежде основным был Jquery.Id, но загрузка по ajax предпочтительней
    • Trigger incoding to footerId – запускаем каждый IML код для элемента footer (изложение ниже)
  • AsHtmlAttributes — собираем IML код и задаем значение containerId (guid) признаку Id
    примечание: применение guid в качестве Id гарантирует уникальность элемента на странице, исключительно актуально для single page application
  • ToDiv — упаковываем полученные признаки в тэг div
    примечание: ToDiv это C# extensions над RouteValueDictionary, следственно без труда дозволено написать свой необходимый вариант 
Container (альтернативный метод)
@Html.Todo().Container(setting =>
             {
                 setting.Id = containerId;
                 setting.Url = Url.Dispatcher()
                                  .Query(new
                                                {
                                                        ClientId = Selector.Incoding.Cookie(CookieManager.ClientId),
                                                        Type = Selector.Incoding.HashQueryString(r => r.Type)
                                                })
                                  .AsJson();
                 setting.Tmpl = Url.Dispatcher()
                                   .Model(new GetTodoByClientQuery.Tmpl { FooterId = footerId })
                                   .AsView("~/Views/Home/Todo_List_Tmpl.cshtml");
                 setting.DependencyId = footerId;
             })

примечание: если в грядущем нужно будет добавить block ui либо другие действия, то сейчас это дозволено делать централизованно

Под капотом

public class ContainerSetting
{
    public string Id { get; set; }

    public string Url { get; set; }

    public string Tmpl { get; set; }

    public string DependencyId { get; set; }
}

public MvcHtmlString Container(Action configure)
{
    var setting = new ContainerSetting();
    configure(setting);

    return helper.When(JqueryBind.InitIncoding | JqueryBind.IncChangeUrl)
                 .Do()
                 .AjaxGet(setting.Url)
                 .OnSuccess(dsl =>
                                {
                                    dsl.Self().Core().Insert.WithTemplateByUrl(setting.Tmpl).Html();
                                    dsl.WithId(setting.DependencyId).Core().Trigger.Incoding();
                                })
                 .AsHtmlAttributes(new { id = setting.Id })
                 .ToDiv();
}
Footer
@(Html.When(JqueryBind.None)
      .Do()
      .Direct(new FooterVm
                        {
                         AllCount = Selector.Jquery.Class("toggle").Length(),
                         IsCompleted = Selector.Jquery.Class("toggle").Is(JqueryExpression.Checked),
                         CompletedCount = Selector.Jquery.Class("toggle")
                                                         .Expression(JqueryExpression.Checked)
                                                         .Length(),
                        }))
      .OnSuccess(dsl =>
                     {
                         string urlTmpl = Url.Dispatcher()
                                             .Model(new TodoFooterTmplVm
                                                        {
                                                                ContainerId = containerId
                                                        })
                                             .AsView("~/Views/Home/Todo_Footer_Tmpl.cshtml");
                         dsl.Self().Core().Insert.Prepare().WithTemplateByUrl(urlTmpl).Html();
                     })
      .AsHtmlAttributes(new { id = footerId })
      .ToDiv())
  • When(JqueryBind.None) — указываем целевые события
    • None – When разрешает указать всякое пользовательское событие, как строку “MySpecialEvent”, но практика показал, что для многих сценариев хватает одного.
  • Do — поведение события
  • Direct — дозволено рассматривать как action заглушка, тот, что не исполняет действий, но может трудиться с данными
    • AllCount – получаем кол-во объектов с классом “toggle”
      примечание: дозволено воспользоваться растяжением Method ( взамен Length ), Дабы вызвать всякий jquery способ, а также написать C# extensions над JquerySelectorExtend
    • IsCompleted — проверяем на присутствие подмеченных объектов с классом “toggle”
      примечание: кому не хватит вероятностей готовых jquery selector, то дозволено воспользоватся Selector.Jquery.Custom(“your jquery selector”)
    • CompletedCount – получаем число подмеченных объектов с классом “toggle”
  • OnSuccess — исполняем позже благополучного заключения AjaxGet
    • Insert prepare data to self by template — вставляем подготовленные (prepare) данные из Direct через template (Todo_Footer_Tmpl ниже ) в нынешний элемент

    примечание: prepare перед тем как вставить данные исполняет селекторы, которые находятся в полях.

  • AsHtmlAttributes — собираем IML код
  • ToDiv — упаковываем полученные признаки в тэг div
Todo List Tmpl

Разметка образца для построения списка todo

@using (var template = Html.Incoding().Template())
{
 <ul>
  @using (var each = template.ForEach()) 
   {
    @using (each.Is(r => r.Active)) 
    { @createCheckBox(true) }
    @using (each.Not(r => r.Active))
    { @createCheckBox(false) }

    <licompleted")">
      <label>@each.For(r=>r.Title)</label>
    </li>
</ul>
}

примечание: начальный код огромнее (удаленна логика элементов), чем представлен на пример, но это сделано для комфорта объяснения template

Что к чему?
  • Html.Incoding().Template() – открываем контекст ( в рамках using ) построения template
  • template.ForEach() — начинаем перебор ( в рамках using ) элементов
  • using(each.Is(r=>r.Active)) — предшествующий вариант условий был в “одну линию”, но Зачастую бывает что нужно исполнить больше трудные действия.
  • createCheckBox — неизвестная C# функция для создания checkbox ( изложение ниже )
  • each.IsInline(r=>r.Active,”completed”) — если поле Active true, тогда возвращаем “completed”
    примечание: также имеются IsNotLine и IsLine. 
  • each.For(r => r.Title) – выводим значение поля Title
    примечание: все обращения к полям происходят на основе указанной модели (да, я вновь о типизации)

Другие элементы

Button del
@(Html.When(JqueryBind.Click)
      .Do()
      .AjaxPost(Url.Dispatcher().Push(new DeleteEntityByIdCommand
                                 {
                                         Id = each.For(r => r.Id),
                                         AssemblyQualifiedName = typeof(Todo).AssemblyQualifiedName
                                 }))
      .OnBegin(r =>
                   {
                       r.WithSelf(s => s.Closest(HtmlTag.Li)).Core().JQuery.Manipulation.Remove();
                       r.WithId(Model.FooterId).Core().Trigger.Incoding();
                       r.WithId(toggleAllId).Core().Trigger.None();
                   })
      .AsHtmlAttributes(new { @class = "destroy" })
      .ToButton(""))
Что к чему ?
  • When(JqueryBind.Click) — указываем целевое событие
  • Do — поведение события
  • AjaxPost — указываем Url, на тот, что делаем ajax запрос
    • Id — значение из Todo
    • AssemblyQualifiedName – получаем имя типа элемента (либо другой иной C# код)
  • OnBegin — исполняем до начала действия (AjaxPost)
    примечание: безусловно положительней будет применять OnSuccess, потому что может случиться оплошность на сервере ( timeout либо что-то другое ) и транзакция будет не полная из-за того, что OnBegin сработает до вызова AjaxPost, но примеры TodoMVC на js framework применяют local storage ( тот, что стремительней чем ajax ) и следственно я не много схитрил, да бы не проигрывать в быстродействие

    • Remove closest LI — удаляем ближайший LI
    • Trigger incoding to footer id – запускаеds_rqvmk!
      • Remove class on closest LI – удаляем класс “completed” у ближайшего LI
      • Add class on closest LI if self is true — добавляем класс “completed”

      примечание: пока в IML не реализована вероятность else, но в версии 2.0 планируется

    • AsHtmlAttributes — собираем IML код, а также устанавливаем значение “toggle” признаку class
    • ToCheckBox — упаковываем полученные признаки в тэг input[type=checkbox]
    Filter by type todo
    @{
        const string classSelected = "selected";
        var createLi = (typeOfTodo,isFirst) => Html.When(JqueryBind.InitIncoding)
                                  .Do()
                                  .Direct()
                                  .OnSuccess(dsl =>
                                                               {
          var type = Selector.Incoding.HashQueryString(r => r.Type);
            if (isFirst)
          dsl.Self().Core().JQuery.Attributes.AddClass(classSelected).If(s => s.Is(() => type == ""));
    
          dsl.Self().Core().JQuery.Attributes.AddClass(classSelected).If(s => s.Is(() => type == typeOfTodo.ToString()));
                                                                })
                                   .When(JqueryBind.Click)
                                   .Do()
                                   .Direct()
                                   .OnSuccess(dsl =>
                                                               {
        dsl.WithSelf(r => r.Closest(HtmlTag.Ul).Find(HtmlTag.A)).Core().JQuery.Attributes.RemoveClass(classSelected);
        dsl.Self().Core().JQuery.Attributes.AddClass(classSelected);                                                   
                                                               })
                                    .AsHtmlAttributes(new { href = "#!".AppendToHashQueryString(new { Type = typeOfTodo }) })
                                    .ToLink(typeOfTodo.ToString());
    }
    
     <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.All,true)        </li>  
     <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.Active,false)    </li>
     <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.Completed,false) </li>
    

    примечание: ещё один пример реализации неизвестных функций в рамках razor view

    Что к чему?
    • When(JqueryBind.InitIncoding) — указываем целевое событие
    • Do — поведение события
    • Direct – ничего не исполняем
    • OnSuccess — исполняем позже успешного заключения
      примечание: для Direct нет различия между OnBegin либо OnSuccess, но OnError и OnBreak работают, так же как и для остальных

      • var type – объявляем переменную, которую потом будем применять в выражениях
      • add class to self if IsFirst is true And type is Empty – добавляем класс, если нынешний элемент является первым и в type пустой
      • add class to self if type is current type – добавляем класс к нынешнему элементу если type равен доводу typeOfTodo
    • When(JqueryBind.Click) — указываем целевое событие
    • Do — поведение события
      примечание: мы не отменяем поведение ссылки, потому что нам необходимо, Дабы браузер обновил location
    • Direct — ничего не исполняем
      • remove class – удаляем класс selected у всех A, которые находятся в ближайшем UL
      • add class to self — добавляем класс selected нынешнему элементу
    • AsHtmlAttributes — собираем IML код, а также устанавливаем признак href
    Filter by type todo (альтернативный метод)
    <li>
        @Html.Todo().LiHash(setting =>
                                {
                             setting.IsFirst = true;
                             setting.SelectedClass = classSelected;
                              setting.Type = GetTodoByClientQuery.TypeOfTodo.All;
                                })                    
    </li>
    

    Абсолютные плюсы !

    В чем же плюсы IML, я постарался раскрыть в прошлой статье, но было не убедительно, следственно испробую ещё раз:

    • Типизация – безусловно всякий глядит через свою призму на типизацию, кто-то считает что доводится писать огромнее кода (это правильно), иным не хватает эластичности, которая присуща не типизированным языкам, но IML это раньше каждого C#, следственно те разработчики, которые его предпочли, я думаю по превосходству оценят данный плюс.
    • Сильные extensions – в статье я привел несколько, но на практике их на много огромнее, Дабы подкрепить свои слова приведу ещё пару:
      • Drop down
        @Html.For(r=>r.HcsId).DropDown(control =>
                                        {
                         control.Url = Url.Action("HealthCareSystems", "Shared");
                         control.OnInit = dsl => dsl.Self().Core().Rap().DropDown();
                         control.Attr(new { @class = "selectInput", style = "width:375px" });
                                        })
        

        примечание: OnInit принимает Action, что разрешает легко масштабировать ваш extensions внедряя в него IML.

        Dialog

        @Html.ProjectName().OpenDialog(setting =>
                                 {
                                    setting.Url = Url.Dispatcher()
                                                     .Model<GroupEditProviderOrderCommand>()
                                                     .AsView("~/Views/ProviderOrder/Edit.cshtml");
                                    setting.Content = "Edit";
                                    setting.Options = options => { options.Title = "Edit Order"; };
                                 })
        

        примечание: для большей эластичности дозволено применять Action в качестве поля, скажем setting.Options это Action.
        Список дозволено продолжать безмерно, но основная идея в том, что IML разрешает исполнять всякие задачи, а html extensions решает задачу с повторным применением.

      • Ещё мощнее extensions
        • Grid — всецело построенный на IML (в ближайшие время будет документация)
          @(Html.ProjectName()
                .Grid<CTRPrintLogModel>()
                .Columns(dsl =>
                         {
                    dsl.Template(@<text>
                                     <span>@item.For(r=>r.Comment)</span>
                                           </text>)           
                                     .Title("Comment");
          
                   const string classVerticalTop = "vertical_top";
                   dsl.Bound(r => r.Time).Title("Time").HtmlAttributes(new { @class = classVerticalTop });
                   dsl.Bound(r => r.Version).Title("Type").HtmlAttributes(new { @class = classVerticalTop });                   
                   dsl.Bound(r => r.PrintDate).Title("Date");
                   dsl.Bound(r => r.Comment).Raw();
                         })
                .AjaxGet(Url.RootAction("GetCTRPrintLogModel", "CTR")))
          
        • Tabs 
          @(Html.Rap()
                .Tabs<Enums.CarePlanTabs>()
                .Items(dsl =>
                       {        
                           dsl.AddTab(Url.Action("RedFlags", "PatientRedFlag"), Enums.CarePlanTabs.RedFlags);
                           dsl.AddTab(Url.Action("Goals", "IncGoal"), Enums.CarePlanTabs.SelfCareGoals);
                           dsl.AddTab(Url.Action("Index", "IncAppointment"), Enums.CarePlanTabs.Appointments);        
                       }))
          

          примечание: всякий разработчик приятель с html extensions может возвести такой элемент под нужды своего плана

      • Работа с hash – в этой статье была рассмотрена только на ярусе IncChangeUrl, но у нас есть:
        • Hash.Fetch – проставляет значения из hash в элементы ( sandbox )
        • Hash.Insert/Update — проставляет значения в hash из элементов
        • Hash.Manipulate – разрешает тонко ( set/ remove by key ) настроить нынешний hash
        • AjaxHash — это аналог Submit, но не для form, а для Hash.
      • Работа с Insert – для реализации TODO мне не пришлось использовать, но в реальных планах повсюду
        • Insert Generic– все примеры выше были построенные на одной модели, но Зачастую бывают сценарии, когда полученные данные являются “контейнером”, для этих целей в Insert есть вероятность указывать с какой частью модели мы трудимся через For, а также template для всякой свой.
          Html.When(JqueryBind.InitIncoding)
              .Do()
              .AjaxGet(Url.Action("FetchComplex", "Data"))
              .OnSuccess(dsl =>
                             {
           dsl.WithId(newsDivId).Core().Insert.For<ComplexVm>(r => r.News).WithTemplateByUrl(urlNewsTmpl).Html();
           dsl.WithId(contactDivId).Core().Insert.For<ComplexVm>(r => r.Contacts).WithTemplateByUrl(urlContactsTmpl).Html();
                             })
              .AsHtmlAttributes()
              .ToDiv()
          
      • Работа с validation (сервер, как заказчик) — в многих js framework есть инструменты для валидации, но IML, как упоминалось не однократно имеет интеграцию с сервером и помощь всяких validation engine (FluentValidation, типовой MVC) без написания добавочного кода.
        • Код command
          if (device != null)
             throw IncWebException.For<AddDeviceCommand>(r => r.Pin, "Device with same pin is already exist");
          
        • Код view
          .OnError(dsl => dsl.Self().Core().Form.Validation.Refresh())
          

        примечание: обработчик OnError должен быть прикреплен к элементу, тот, что вызывает action ( submit, ajaxpost or etc )

      • Поменьше скриптов – с пристрастием плана js framework требует написания множества js файлов, но IML имеет фиксированный (плагины не в счет) комплект библиотек
      • Типизированные template – я о типизации в целом, но для построения образцов это исключительно значимо
      • Замена template engine — выбирайте всякий, а синтаксис тот же
      • Готовая инфраструктура – IML это часть Incoding Framework и в различии от js framework у нас полная ( сервер / заказчик / unit testing ) инфраструктура для разработки планов, которая узко интегрирована между собой.

      Завершение

      При реализации todo на IML я придерживался правила: поменьше обновлений странице, то есть пересчитывал все на заказчике, но практика (наших планов) показывает, что Почаще тесным местом бывает именно сервер, потому что многие действия не допустимы либо не предпочтительны на заказчике, скажем

      Немыслимы (по причине продуктивности):

      • Paginated – если в базе сотни тысяч записей, то такой объем не верно передавать на заказчика
      • Order – та же повод
      • Where — та же повод

      Не предпочтительны могут быть расчеты, такие как трудные вычисления (всеобщую сумму заказов с учетом налога) на основе значений полей, комфортней будет отправить на сервер запрос (с данными полей) и итог вставить.

      Вновь IML ))

      В рамках IML вычисления дозволено решить следующими методами:

      • Одиночное значение
        var val = Selector.Incoding.AjaxGet(url);
        dsl.WithId(yourId).Core().JQuery.Attributes.Val(val);
        
      • Комплект данных 
        dsl.With(r => r.Name(s => s.Last)).Core().Insert.For<ContactVm>(r => r.Last).Val();
        dsl.With(r => r.Name(s => s.First)).Core().Insert.For<ContactVm>(r => r.First).Val(); 
        dsl.With(r => r.Name(s => s.City)).Core().Insert.For<ContactVm>(r => r.City).Val();
        

      Дозволено длинно рассказывать про вероятности IML (и Incoding Framework), но статья и так получилось огромный, следственно, те кто захочет продолжить постигать наш инструмент сумеют обнаружить материалы в сети. Я понимаю, подтвердить то, что IML горазд решать задачи не дрянней знаменитых js framework весьма трудно, но в следующих статьях будет обзор реализаций autocomplete, Tree View, grid и других трудных задач, которые продемонстрируют ещё огромнее вероятностей.

      P.S. Как неизменно рад критики и примечаниям )))

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB