четверг, 4 ноября 2010 г.

Переезжаю на другой хостинг

Перевожу свой блог на http://thekazarin.ru/. Все следующие посты будут публиковаться там.

воскресенье, 10 октября 2010 г.

MVC. Razor vs NHaml

Когда первый раз читал про Razor View Engine в блоге Скота Гатри и наткнулся вот на такое описание цикла foreach:

clip_image002

Первое, что пришло в голову: «Так это же почти как NHaml!». В этой статье попытаюсь сравнить насколько эти два движка близки по удобству программирования. Для этого создам два пустых проекта с названиями RazorMVCApplication и NHamlMVCApplication (предполагается, что NHaml установлен и настроен).

Пусть модель будет предоставлять данные из базы ViewEngines, которая находится на Microsoft SQL Server 2008 Express. В этой базе будет только одна таблица с таким же названием и вот такой схемой:

clip_image004

В виде данных используем информацию о существующих движках для MVC Framework:

clip_image006

Сгенерируем модель по этой базе данных с помощью LinqToSQL для обоих наших проектов.

На следующем шаге создадим HomeController. У нас автоматически сгенерируется метод Index(). Создадим для него View (теперь все действия мы совершаем для Razor). Так как у нас нет master page, не забудем снять галочку с Select master pag). Если мы запустим наше приложение, то увидим пустую страницу. Именно она соответствует коду, автоматически сгенерированному в нашем View.

Теперь попробуем отобразить заголовок окна, заданный в контроллере. Для этого в методе Index() добавим следующую строку перед return View():

ViewData["Title"] = "Hello, Razor!";

* This source code was highlighted with Source Code Highlighter.

А также немного изменим секцию title в представлении:

<title>@View.Title</title>

* This source code was highlighted with Source Code Highlighter.

Это все, что нам нужно сделать для того, чтобы изменить заголовок из контроллера.

Давайте сделаем то же самое для проекта с NHaml:

Поскольку наше представление должно лежать во View/Home/Index, то создадим каталог Home и добавим в него пустой текстовый файл с именем Index.haml. Запустив приложение убедимся, что открывается чистая страница.

Чтобы задать заголовок страницы, напишем следующее:

%html
  %head
    %title="My cool title"
  %body

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

Получим значение заголовка, заданного в контроллере:

%html
  %head
    %title= ViewData.Title
  %body

 

Теперь вернемся к Razor и отобразим содержимое единственной таблицы базы данных.

В контроллере добавим:

using (var dc = new MVCApplicationDataContext())
{
  ViewData["ViewEngines"] = (from engine

in dc.ViewEngines select engine).ToList();
}

Во View:

<ul>
@foreach(var engine in @View.ViewEngines) {
           <li>@engine.Name</li>   }
</ul>

Повторим то же самое и для NHaml:

%body
    %ul
      -foreach (var engine in ViewData.ViewEngines)
        %li=engine.Name

Если в проекте есть куски представления, которые можно переиспользовать, то в Razor есть метод @Html.Partial(“PartialName”), который дает возможность вставить представление из другого файла. В NHaml для этого используются файлы с имененем, начинающимся с символа “_”. То есть, если мы хотим вставить представление из файла с именем _partialname, то напишем так:

%body
    _partialname
    %ul
      -foreach (var engine in ViewData.ViewEngines)
        %li=engine.Name

Большинство языковых конструкций очень похожи, и принцип их использования одинаков. Но тогда встает вопрос об удобствах, предоставляемых Visual Studio, ведь именно они буду определять решающую роль в скорости разработки. И тут в случае NHaml мы натыкаемся на такую ситуацию: intellisense в виде плагина есть только для VisualStudio 2008, когда будет для 2010 никто не знает. Есть утилита позволяющая подсвечивать код, но это помогает незначительно. Для Razor intellisense появится, скорее всего, вместе с релизом MVC 3.

пятница, 8 октября 2010 г.

Windows Phone 7. Работа с камерой

В этой статье расскажу о том, как можно получать изображения с камеры в Windows Phone 7. Нужно понимать, что невозможно получить доступ к камере напрямую. Можно только воспользоваться стандартной утилитой, которая позволяет сделать фотографию и передать ее обратно в приложение. Такое поведение утилит в Windows Phone 7 носит название задач выбора (choosers). Помимо этого есть задачи выполнения (launchers), которые ведут себя так же, как и задачи выбора, но не передают никаких данных обратно в приложение. Благодаря им можно из вашего приложения вызывать адресную книгу, прерывать ваше приложение телефонным вызовом и т.д. Обо всем этом подробнее поговорим в следующих статьях.

Давайте попробуем получить изображение с камеры. Для этого создадим новый проект Windows Phone Application, назовем его, например, WindowsPhoneCameraApplication. Изменим заголовки и добавим элемент Image с именем cameraImage на страницу:

clip_image002

Пусть по инициализации приложения мы будем получать возможность сделать снимок, после чего он автоматически отображался бы в cameraImage.

Для работы с камерой нам понадобится пространство имен Microsoft.Phone.Tasks, в котором содержится chooser CameraCaptureTask.

Напишем такой код:

    public partial class MainPage : PhoneApplicationPage
    {
        CameraCaptureTask camera;

        public MainPage()
        {
            InitializeComponent();

            camera = new CameraCaptureTask();
            camera.Completed += SendToCameraImage;
            camera.Show();
        }

        void SendToCameraImage(object sender, PhotoResult agrs)
        {
            if (agrs.TaskResult == TaskResult.OK)
            {
                var bmp = new BitmapImage();
                bmp.SetSource(agrs.ChosenPhoto);
                cameraImage.Source = bmp;
            }
        }
    }


Мы используем обработчик SendToCameraImage по событию завершения работы камеры для того, чтобы сохранить полученный снимок в формате bmp из потока, содержащегося в ChosenPhoto. Метод Show просто инициализирует chooser по работе с камерой.

В эмуляторе мы, к сожалению, не можем получить доступ к подключенной к компьютеру камере. Поэтому все полученные изображения представляют собой белый прямоугольник с черным прямоугольником внутри, находящимся каждых раз у разных стенок экрана.

Попробуем запустить без отладки, нажав Ctrl+F5:

clip_image004

Важным является то, что при запуске приложения по работе с камерой наше приложение переходит в состояние захоронения. То есть сохраняется состояние программы, для того, чтобы запустить ее после получения снимка с камеры. Именно по этой причине во время запуска с отладчиком при запуске  утилиты по работе с камерой Visual Studio рапортует о завершении приложения и возвращается в режим редактирования. Как можно продолжить отладку после завершения работы с камерой? Сделав снимок и нажав кнопку «Accept», нужно в течение 10 секунд нажать на кнопку F5, и Visual Studio снова подключится к приложению.

В следующей статье мы попробуем сохранить нашу фотографию в локальное хранилище, сделать возможность просмотра сохраненных фотографий, а также посмотрим на навигацию между страницами приложения.

пятница, 28 мая 2010 г.

[Перевод] Image Generation зарелизен на CodePlex

Перевод статьи Скота Хантера (http://blogs.msdn.com/scothu/archive/2008/08/21/image-generation-is-released-to-codeplex.aspx).

Я очень рад объявить, что на этой неделе мы выпустили на сайте ASP.NET CodePlex новую функцию под названием Image Generation. Вы можете получить прямую ссылку, просто кликнув сюда: http://www.codeplex.com/aspnet/Wiki/View.aspx?title=WebForms&referringTitle=Home.

Была особенность в первой бета-версии Visual Studio 2005 (Whitbey), названная DynamicImage, которая элемент управления для генерации изображений и сервиса изображений для обслуживания их. Эту возможность было печально убирать, потому что некоторые другие части фрэймворка зависели от нее.

Image Generation обычно служит для того, чтобы вернуть это тип функции во фрэймворк. Вот несколько основных моментов, которые делает это новая фича:

Новый элемент управления ASP.NET – GeneratedImage. Этот элемент управления – наследник asp:Image, поддерживающего подключение к Image Handler и передающего параметры ему. Если вы поместите этот элемент на странице и перейдете в режим дизайна, то он будет хромированным, и, если кликнуть по нему, то автоматически сгенерируется ImageHandler и передаст URL в него. Параметры, такие как первичный id и марки, могут быть переданы в элемент управления и будут автоматически отправлены в обработчик.

ImageHandler, являющийся реализацией IHttpHandler, предоставляющим поддержку для многих вещей, основанных на изображениях:

  • Трансформация (изменение размера, водяные знаки, преобразования, определенные пользователем)
  • Кэширование на клиенте
  • Кэширование на сервере
  • Доступ к параметрам, переданным от GeneratedImage
  • Обеспечение простого механизма возврата изображений

Если вы посмотрите на сайте, то там есть три примера использования GeneratedImage:

  • Simple Generated Image показывает, как можно создать простой bitmap и вернуть его
  • Databased Images демонстрирует, как можно использовать эту функцию для отображения изображений, хранящихся в базе данных
  • Custom Image Transforms дает представление, как писать пользовательские трансформации, добавляющие лого ASP.NET к изображению
Мы рассматриваем возможность добавления этой фичи в следующую версию .NET и хотелось бы услышать ваше мнение. Пожалуйста, попробуйте и поделитесь своими ощущениями!

[Перевод] Улучшена поддержка сторонних элементов управления и Dynamic Data в ASP.NET 4.0 и DevExpress Grid и Dynamic Data

Перевод статьи Скота Хантера (http://blogs.msdn.com/scothu/archive/2009/03/10/better-support-for-3rd-party-controls-and-dynamic-data-in-asp-net-4-0-and-devexpress-grid-and-dynamic-data.aspx).

Одна из вещей, над которой мы работали, является поддержка в Dynamic Data для сторонних элементов управления, например Grid, возможности хостить динамические элементы управления. По существу, позволять разработчикам использовать элементы управления, которые им нравятся или более функциональны, нежели доступные элементы управления в ASP.NET, поддерживающие Dynamic Data.

В первой версии Dynamic Data мы попытались работать в различных ограничениях, поскольку она поставлялась в Service Pack, который ограничивал возможные изменения в фрэймворке. В основном мы смогли добавить новый API, но было мало возможностей для изменения существующего API.

Одним из ограничений для элементов управления было то, что для поддержки Dynamic Data, они должны были наследоваться от DataBoundControl, потому что не было интерфейсов, которые могли реализовывать элемент управления для поддержки основных операций по привязке данных. Некоторые поставщики элементов управления хотят иметь возможность наследовать свои элементы управления от Control для того, чтобы сделать их настолько легкими, насколько это возможно и получить максимальную производительность.

Для решения этого в .NET 4.0 мы добавили новые интерфейсы, которые позволяют реализовывать привязку данных, а также указывать отображает ли элемент управления одиночный элемент или список элементов. Вот классификация новых интерфейсов:

public interface IDataBoundControl

Интерфейс для доступа к общим свойствам связи данных с элементами управления.

string DataSourceID { get; set; }

Возвращает или устанавливает идентификатор элемента управления, из которого, связанный с данными элемент управления получает свой список элементов.

IDataSource DataSourceObject { get; }

Возвращает актуальный источник данных, когда DataSourceId задано.

object DataSource { get; set; }

Устанавливает или возвращает объект, из которого элемент управления, связанный с данными, получает свой список элементов.

string[] DataKeyNames {get; set; }

Принимает или возвращает массив, содержащий имена полей с первичными ключами для элементов, отображенных элементом управления.

DataBoundControlMode Mode { get; }

Определяет находится ли элемент управления в режиме ReadOnly. Редактирование или режим вставки.

string DataMember { get; set; }

Принимает или возвращает имя списка данных, с которым связан элемент управления в тех случаях, когда источник данных содержит более чем один отличный список элементов данных.

public interface IDataBoundListControl

Интерфейс для элементов управления с привязкой данных, отображающий несколько строк и предоставляющий возможность выбора.

DataKeyArray DataKeys { get; }

Возвращает коллекцию объектов DataKey, представляющую ключевое значение данных для каждой строки из GridView.

DataKey SelectedDataKey { get; }

Возвращает объект DataKey, содержащий значения ключей данных для выбранной строки элемента управления GridView.

int SelectedIndex { get; set; }

Возвращает или устанавливает индекс выбранной строки в GridView.

string[] RowClientIDSuffix { get; set; }

 

bool EnablePersistedSelection { get; set; }

Возвращает или устанавливает выборку на основе индекса ключей данных.

IDataBoundItemControl

Интерфейс для элементов управления, связанных с данными, отображающий единичный элемент.

DataKey DataKey { get; }

Возвращает объект DataKey, представляющий значение ключа данных строки в элементе управления.

IFieldControl

Interface for data bound controls that can automatically generate their fields based on data.

IAutoFieldGenerator FieldsGenerator { get; set; }

Возвращает или устанавливает IAutoFieldGenerator, создающий поля.

IDataBoundControl реализуется элементом управления для индикации поддержки привязки данных. Это включает источник данных, первичные ключи и режим, в котором работает элемент управления. IDataBoundListControl указывает элементу управления, отображающему данные в список и поддерживающему выбор. IDataBoundItemControl определяет элемент управления, отображающий одну запись одновременно. И IFieldControl - для элементов управления, как GridView или DetailView, имеющих возможность автоматически генерировать свои столбцы. Эти новые интерфейсы реализуются для всех стандартных элементов управления данными в 4.0, включая ListView, GridView, DetailsView и FormView. Если сторонние элементы управления поддерживают эти интерфейсы, то могут быть использованы с Dynamic Data.

Один из поставщиков элементов управления, DevExpress, недавно ввела Dynamic Data без поддержки этих интерфейсов в Grid Control. Вот очень хороший скринкаст от Mehul Harry, который демонстрирует их grid и Dynamic Data в действии. Посмотреть скринкаст можно здесь: http://community.devexpress.com/blogs/aspnet/archive/2009/02/01/asp-net-dynamic-data-and-devexpress-grid.aspx. Пожалуйста, посмотрите и дайте Mehul знать, что вы об этом думаете!

четверг, 27 мая 2010 г.

[Перевод] Улучшение работы с данными в .NET

Перевод статьи Скота Хантера (http://blogs.msdn.com/scothu/archive/2009/10/20/data-enhancements-in-net-4-visual-studio-2010-beta-2.aspx).

В среду мы выпускаем публичную версию .NET 4 / Visual Studio 2010 Beta 2 и это принесет много крутых улучшений в управление данными в ASP.NET и Entity Framework. Я собираюсь углубиться в несколько возможностей, связанных с особенностями данных, и вы можете больше прочитать обо всех этих изменениях в ASP.NET по ссылке: http://www.asp.net/learn/whitepapers/aspnet40/. Этот документ содержит весьма подробный перечень всех изменений, которые мы сделали в ASP.NET.

Вот несколько моих любимых возможностей, связанных с данными:

1) Entity Framework теперь может образовывать как наборы сущностей, так и отдельные сущности. Это значит, что когда я ссылаюсь на таблицу, сама таблица будет называться "Продукты", но фактически класс, с которым я работаю в своем приложении, будет называться "Продукт". Это выглядит более естественно, чем в Entity Framework 1, в котором я бы написал:

Products product = new Products();

В то время, как в 4.0 это будет выглядеть так:

Product product = new Product();

Что кажется более естественным и лучше выглядит в моем коде.

Вот графический интерфейс в Entity Model Wizard для включения этого (замечание: оно включено по умолчанию)

1

2) Entity Framework теперь поддерживает возможность включить "внешние ключи" в модели данных. В первой версии Entity Framework, если бы у меня была таблица Product, содержащая CategoryID, ссылающиеся на запись в таблице Category, генерируемой Entity Framework, то модель преобразовала бы CategoryID в навигационное свойство, которое бы напрямую уходило в таблицу категорий. Хоть это и упрощало некоторые сценарии, но делало веб-сценарии более сложными. Обычно я бы представляю это в использовании элемента DropDownList, который будет содержать первичный ключ и имя записи из таблицы категорий. При сохранении записи я просто хочу присвоить выбранному CategoryID из DropDownList классу Product. Но с навигационными свойствами я бы пришел к некоторому очень некрасивому и неочевидному коду для задания CategoryID, если его не существует. Entity Framework 4 теперь включает в себя способность иметь столбцы внешних ключей, добавляемых непосредственно в сущности, предоставляющих мне возможность установить внешний ключ или навигационное свойство, облегчая программирование веб сценариев:

         2

3) Теперь доступна поддержка QueryExtender для EntityDataSource. В релизах .NET 4 Beta 1 and in the Dynamic Data Preview на CodePlex мы представили очень интересный расширяющий элемент управления для LinqDataSource, названный QueryExtender. Мы создали этот контрол в ответ на отзывы, которые мы получили после релиза Dynamic Data 1.0, что наши клиенты хотели более легкий способ фильтрации или поиска данных, чем тем, которые предоставляли контолы источников данных, например, «Как следует выполнять поиск». Этот паттерн элементов управления источников данных может получиться довольно сложным, и мы хотели предоставить что-нибудь простое. QueryExtender предоставляет следующие виды поиска:

Поиск: Поиск строки в любом числе столбцов

Диапазон: фильтры данных базируются на том, если значение столбца находится в заданном диапазоне

Свойства : фильтры, основанные на соответствии значения в столбце

При необходимости: событие срабатывает, когда разработчик может настроить выражение LINQ.

Вот пример использования QueryExtender с EntityDataSource. Он принимает значение из TextBox1 и сравнивает его с полем ProductName, и только возвращает строки, которые содержат текст из TextBox1 в поле ProductName:

<asp:EntityDataSource ID="EntityDataSource1" runat="server"
        ConnectionString="name=NORTHWNDEntities"
        DefaultContainerName="NORTHWNDEntities" EnableDelete="True"
        EnableFlattening="False" EnableInsert="True" EnableUpdate="True"
        EntitySetName="Products">
</asp:EntityDataSource>
<asp:QueryExtender ID="QueryExtender1" runat="server" TargetControlID="EntityDataSource1">
    <asp:SearchExpression SearchType="Contains" DataFields="ProductName">
        <asp:ControlParameter ControlID="TextBox1" />
    </asp:SearchExpression>
</asp:QueryExtender>

4) Расширенный метод EnableDynamicData. Мы ввели Dynamic Data в .NET 3.5 SP1, но он имел некоторые серьезные требования к разработчику: обязательное использование Linq к SQL или Entity Framework, требование к разработчику, чтобы начать новый проект, надо было получить файлы поддержки Dynamic Data, предоставляющие различные модели программирования. В Beta 2 мы добавили эту новую возможность, которая может быть включена для элементов управления нашими данными следующим образом:

ListView1.EnableDynamicData(typeofProduct))

Эта единственная строка кода автоматически добавит многие из особенностей, которые обеспечивает Dynamic Data:

- Автоматическая валидация

- Поддержка Data Annotations в объектах для валидации и проверки свойств отображения

- Поддержка местных шаблонов для настройки поведения пользовательского интерфейса в зависимости от типа данных

Это позволит разработчику использовать возможности Dynamic Data без радикального изменения их приложений или использования Linq для SQL или Entity Framework.

Есть много других изменений и обновлений в нашей поддержке данных, и я попытаюсь писать блог о ней в течение следующих нескольких недель.