воскресенье, 30 августа 2009 г.

ASP.NET MVC: ActionLink with Image

Занадобилась мне ссылка с картинкой вместо текста, те ActionLink с картинкой вместо текста.


Попытки передать вместо текста ссылки готовый тег '<img src='Icons/edit.png'/>' ни к чему хорошему не привели, потому как оно выводится через метод HttpUtility.HtmlEncode, который заменяет в тексте знаки '<' '>' на '&lt;' и '&gt;' соответственно.
Сделал с помощью Extension methods (методы-расширения) для класса HtmlHelper.

    public static class Extensions

    {

        public static string ActionLinkImage(this HtmlHelper htmlHelper, string altImageText, string imagePath, string actionName)

        {

            return ActionLinkImage(htmlHelper, altImageText, imagePath, actionName, new RouteValueDictionary(), new RouteValueDictionary());

        }

 

        public static string ActionLinkImage(this HtmlHelper htmlHelper, string altImageText, string imagePath, string actionName, object routeValues)

        {

            return ActionLinkImage(htmlHelper, altImageText, imagePath, actionName, new RouteValueDictionary(routeValues), new RouteValueDictionary());

        }

 

        public static string ActionLinkImage(this HtmlHelper htmlHelper, string altImageText, string imagePath, string actionName, object routeValues, object htmlAttributes)

        {

            return ActionLinkImage(htmlHelper, altImageText, imagePath, actionName, new RouteValueDictionary(routeValues), new RouteValueDictionary(htmlAttributes));

        }

 

        public static string ActionLinkImage(this HtmlHelper htmlHelper, string altImageText, string imagePath, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)

        {

            const string linkTextReplacement = "F14E9A0EB8C4";

            string actionLink = System.Web.Mvc.Html.LinkExtensions.ActionLink(htmlHelper, linkTextReplacement, actionName, routeValues,htmlAttributes);

 

            return actionLink.Replace(linkTextReplacement, String.Format(@"<img src='{0}' alt='{1}'/>", imagePath, altImageText));

        }

    }



А применяется оно так:
'<%= Html.ActionLinkImage("Edit", "Icons/edit.png", "Edit", new { id = item.EmployeeId }, new {@class = "ImageLink"})%'>
Результат:
'<A class=ImageLink href="about:/Employee/Edit/100"><IMG alt=Edit src="about:Icons/edit.png">'</A>

суббота, 29 августа 2009 г.

Silverlight: SketchFlow для прототипирования интерфейсов

Очень интересная статья с примером использования SketchFlow для создания прототипов приложения. И перевод на русский Владимира Юнева.

пятница, 28 августа 2009 г.

ASP.NET MVC: DropDownList

При редактировании некоторых полей объекта очень часто необходимо использование контрола DropDownList. А чтоб его заполнить данными нужен объект типа IEnumerable.

Для примера понадобятся слудующие сущности EmployeeEntity, JobEntity

public class EmployeeEntity
  {
    public virtual int EmployeeId { get; set;}
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual String JobId { get; set; }
  }


* This source code was highlighted with Source Code Highlighter.


public class JobEntity
  {
    public virtual string JobId { get; set; }
    public virtual string JobTitle { get; set; }
  }


* This source code was highlighted with Source Code Highlighter.


Что бы удобно передать во View модель данных содержащую как экземпляр Employee так и список Job`ов создаем класс обертку:
public class EmployeeEditViewData
  {
    public EmployeeEntity Employee;
    public IEnumerable<SelectListItem> Jobs;
  }


* This source code was highlighted with Source Code Highlighter.


Теперь необходимо создать Action для Employee контроллера
  1. public ActionResult Edit(int id)
  2.     {
  3.       EmployeeEntity employeeEntity = _employeeRepository.EditById(id);
  4.       IEnumerable<SelectListItem> jobs =
  5.         Domain
  6.         .CurrentSession
  7.         .CreateCriteria<Job>()
  8.         .List<Job>()
  9.         .Select(j => new SelectListItem
  10.                  {
  11.                    Text = j.JobTitle,
  12.                    Value = j.JobId,
  13.                    Selected = employeeEntity.JobId == j.JobId
  14.                  });
  15.  
  16.       EmployeeEditViewData viewData = new EmployeeEditViewData
  17.                         {
  18.                           Employee = employeeEntity,
  19.                           Jobs = jobs
  20.                         };
  21.       return View("Edit", viewData);
  22.     }
* This source code was highlighted with Source Code Highlighter.

А теперь по порядку:
строка 3 - получение экземляра объекта EmployeeEntity;
строки 4-14 - получение экземляра IEnumerable Jobs;
строки 16-20 - создаем EmployeeEditViewData и инициализируем поля ранее получеными объектами;

Для данного action необходимо создать строго типизированную view на основе класса EmployeeEditViewData. У меня студийный генератор не смог сгенерить заготовку view для редактирования полей, но ничего не мешает это сделать самому.
Для поля в котором нам понадобится DropDownList пишем следующий код:
    <p>
      <label for="JobId">
        Job:</label>     
      <%= Html.DropDownList("JobId",Model.Jobs) %>      
    </p>


* This source code was highlighted with Source Code Highlighter.


В общем то все.

четверг, 20 августа 2009 г.

ASP.NET + NHibernate + Oracle и Pagination

Постраничный вывод в ASP.NET + NHibernate + Oracle.
Выдергивать из базы данные постранично желание отнюдь не запретное, посему решено было его удовлетворить.

public class InsuredController : Controller
  {
    private ISessionFactory _SessionFactory;  

    private int? currentPage=0;
    private int pageSize=25;

    //...

    public ActionResult Index(int? pageNumber)
    {      
      currentPage = pageNumber??0;

      ICriteria creteria = _SessionFactory.OpenSession().CreateCriteria(typeof(Foo.FooEntity));
      
      creteria.SetFirstResult(pageSize * (int)currentPage).SetMaxResults(pageSize);
      
      ViewResult vresult = View(creteria.List<Foo.FooEntity>());
      vresult.ViewData["PageNumber"] = pageNumber;
      return vresult;
    }
}

* This source code was highlighted with Source Code Highlighter.


Все бы хорошо, но дальше 0 страницы данные не возвращаются, а все потому что в базу уходит запрос
SELECT  *
 FROM  (SELECT  this_.ID AS ID1_0_0_,
          this_.CREATE_DATE AS CREATE2_0_0_,
          this_.DISABLE_DATE AS DISABLE3_0_0_,
          this_.EDIT_DATE AS EDIT4_0_0_,
          this_.EXCHANG_STAT AS EXCHANG5_0_0_
      FROM  FOO this_)
WHERE  ROWNUM BETWEEN 25 AND 75


* This source code was highlighted with Source Code Highlighter.


А вот оно что - BETWEEN vs ROWNUM.
А в школьном курсе оракловой физики четко написано что ROWNUM - это псевдостолбец, значение которого присваивается строке уже после выполнения предикатов запроса, но перед выполнением сортировок и агрегирований. В то же время оператор BETWEEN ограничивает выборку по столбцу значение которого еще не было присвоено, те равно NULL. А все операции сравнения чего либо с значением NULL = FALSE. Вот и получаем пустой результат.

Решение этой проблемы простое - заменить в конфиге значение своейства dialect - NHibernate.Dialect.OracleDialect на NHibernate.Dialect.Oracle10gDialect или NHibernate.Dialect.Oracle9iDialect

Результирующий запрос:
SELECT  *
 FROM  (SELECT  row_.*, ROWNUM rownum_
      FROM  (SELECT  this_.ID AS ID1_0_0_,
               this_.CREATE_DATE AS CREATE2_0_0_,
               this_.DISABLE_DATE AS DISABLE3_0_0_,
               this_.EDIT_DATE AS EDIT4_0_0_,
               this_.EXCHANG_STAT AS EXCHANG5_0_0_
           FROM  FOO this_) row_
      WHERE  ROWNUM <= :p0)
WHERE  rownum_ > :p1


* This source code was highlighted with Source Code Highlighter.