вторник, 2 августа 2011 г.

Сохранение порядка сортировки выборки в Linq

На MSDN’овском форуме задали вопрос о сохранении порядка сортировки выборки при использовании Linq. Задача достаточно типовая, поэтому решил написать небольшой мануал, как это сделать используя Dynamic Linq. Для упрощения пусть данные отображается у нас в DataGrid’e и сортируются нажатием мышкой на заголовок столбцов.

Dynamic Linq

Библиотека Dynamic Linq  входит в набор примеров кода для Visual Studio 2008 (C#, VB). После выкачивания можно найти исходный код, документацию и пример использования в папке \LinqSamples\DynamicQuery.

Проект с примером использования отлично собирается как под .Net Framework 3.5, так и под 4.0.  Сам код библиотеки вынесен в namespace System.Linq.Dynamic и находится в файле Dynamic.cs. Для использования можно скопировать код к себе в проект или создать отдельный проект с библиотекой.

Использование

Итак у нас есть форма, на ней DataGrid с гордым именем dataGrid1.

Простой класс:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string NickName { get; set; }
    public DateTime BirthDate { get; set; }
}

При инициализации формы подсовываем Grid’у в качестве источника данных массив Person:

var persons = new Person[] 
{
    new Person{FirstName = "Сидр", LastName = "Сидоров", NickName = "sid", BirthDate = DateTime.Today.AddYears(-22)},
    new Person{FirstName = "Петр", LastName = "Петров", NickName = "pit", BirthDate = DateTime.Today.AddYears(-21)},
    new Person{FirstName = "Иван", LastName = "Иванов", NickName = "ian", BirthDate = DateTime.Today.AddYears(-20)},
};
this.dataGrid1.ItemsSource = persons;

Данные отображаются и сортируются нажатием на заголовки колонок, но порядок сортировки не сохраняется между сеансами.

Итак, приступим.

Первое, что нам нужно сделать, это перенести код библиотеки Dynamic Linq  к себе в проект. Это можно сделать двумя способами:

  1. Создать класс и скопировать код из полученного ранее проекта;
  2. Сразу добавить файл в себе в проект (в Solution Explorer’e щелкнуть право кнопкой на проект, и выбрать Add->Existing Item).

У DataGrid’а добавляем в обработчик события Sorting код, который будет сохранять поле и порядок сортировки в конфигурационном файле

private void dataGrid1_Sorting(object sender, DataGridSortingEventArgs e)
{
    IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly();
    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("LastSort.txt", FileMode.Create, store))
    {
        using (StreamWriter writer = new StreamWriter(stream))
        {
            writer.WriteLine(String.Format("{0} {1}", e.Column.SortMemberPath,
                (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending));
        }
    }
}

Небольшое пояснение по поводу IsolatedStorage
IsolatedStorage – это механизм позволяющий сохранять данные в “виртуальные” папки в зависимости от выбранной области ограничения видимости. Использованная функция GetUserStoreForAssembly() возвращает нам “путь” который уникален для пользователя  и Assembly, т.е. другие приложения и пользователи не будут иметь доступ к файлу LastSort.txt в котором хранятся данные об используемом порядке сортировки.

Небольшое пояснение по поводу (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending
Дело в том, что Column.SortDirection является Nullable, то есть кроме ListSortDirection.Ascending и ListSortDirection.Descending принимает еще и значение NULL, которое и является значением по умолчанию. Помимо этого в  DataGridSortingEventArgs e содержится предыдущее состояние сортировки, поэтому приходится использовать такую конструкцию.

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

private void Window_Closing(object sender, CancelEventArgs e)
{
    foreach (var c in this.dataGrid1.Columns)
    {
        if (c.SortDirection.HasValue)
        {
            IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("LastSort.txt", FileMode.Create, store))
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.WriteLine(String.Format("{0} {1}", c.SortMemberPath, c.SortDirection));
                }
            }
            break;
        }
    }
}

Пишем функцию которая выдергивает значение из файла в изолированном хранилище

private string GetLastSort()
{
    IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly();
    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("LastSort.txt", FileMode.OpenOrCreate, store))
    {
        using (StreamReader reader = new StreamReader(stream))
        {
            return reader.ReadLine() ?? "NickName Descending";
        }
    }
}

После этого меняем подключение данных для DataGrid’а на

this.dataGrid1.ItemsSource = persons.AsQueryable<Person>().OrderBy(GetLastSort()).Select("new (FirstName, LastName, NickName, BirthDate)");

среда, 20 апреля 2011 г.

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 5: Designing the User Interface and User Experience

>>В начало

Designing the User Interface and User Experience (23%)

  • Design for separation of concerns.
    • This objective may include but is not limited to: presentation patterns that use view models, MVVM
  • Design Windows Phone 7 control usage.
    • This objective may include but is not limited to: design control usage as described in UI Design and Interaction Guide for Windows Phone 7; design proper use of PanoramaControl and PivotControl; choose when to use the Panorama Control and PivotControl; recommend when to use ApplicationBar
  • Recommend keyboard layout for a given situation.
    • This objective may include but is not limited to: InputScope property
  • Design for system themes, accent color, and screen orientation.
    • This objective may include but is not limited to: built-in styles that use system themes and accent colors, ApplicationBar icons (size, transparency), landscape, portrait

Ссылки:

Designing the User Interface and User Experience (23%)

RU links: Video (EN)

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 4: Designing the Application Architecture

>>В начало

Designing the Application Architecture (21%)

  • Design for threading.
    • This objective may include but is not limited to: use of the composition thread
  • Monitor and tune performance.
    • This objective may include but is not limited to: frame rate counter; cache visualization; redraw regions; bitmap caching; memory usage limitations; plan for power consumption; tune bandwidth consumption; performance counters
  • Manage the application life cycle.
    • This objective may include but is not limited to: tombstoning; response to PhoneApplicationService events (Launching, Activated, Deactivated, Closing)
  • Prepare the application to meet Windows Phone 7 marketplace requirements.
    • This objective may include but is not limited to: Windows Phone 7 Application Certification Requirements; design for localization and globalization; plan for trial versions; work with WMAppManifest.xml; design for icon requirements for marketplace

Ссылки:

Designing the Application Architecture (21%)

RU Links:

Other links:

Video (EN):

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 3: Working with Platform APIs, Tasks, and Choosers

>>В начало

Working with Platform APIs, Tasks, and Choosers (21%)

  • Design and implement sensor interaction.
    • This objective may include but is not limited to: choose which sensors are appropriate for your application; design location awareness (when to use different levels of GeopositionAccuracy); location awareness system setting
  • Plan for and implement the use of Tasks and Choosers.
  • Plan for and implement multitouch and gestures.
    • This objective may include but is not limited to: manipulation events (ManipulationStarted, ManipulationCompleted, ManipulationDelta)
  • Design and implement application navigation.
    • This objective may include but is not limited to: pass parameters (NavigationContext API), manipulate the navigation stack (NavigationService API), use of the Back button, PhoneApplicationPage class and PhoneApplicationFrame class and the difference between these two classes

Ссылки:

Working with Platform APIs, Tasks, and Choosers (21%)

RU Links:

EN Links:

Video (EN):

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 2: Designing and Implementing Notification Strategies

>>В начало

Designing and Implementing Notification Strategies (17%)

  • Plan for and implement push notifications in the application.
    • This objective may include but is not limited to: choose method for notifying user of application’s state/status (tile, toast, RAW); respond to notifications; registration for notifications
  • Plan for and implement push notifications on the server.
    • This objective may include but is not limited to: when to use toast, tile, and raw; plan for receiving the unique device URL
  • Create and update live tiles.
    • This objective may include but is not limited to: update background image, numbers, and text

Ссылки:

Designing and Implementing Notification Strategies (17%)

RU Links: EN Links: Video (EN):

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 1: Designing Data Access Strategies

>>В начало

Designing Data Access Strategies (19%)

  • Send and receive data.
    • This objective may include but is not limited to: design connection mechanisms for communicating with external web services; plan how to consume and parse data from web services (for example, WCF and WS*); ensure a trusted transfer of data to and from a phone
  • Design a data storage strategy.
    • This objective may include but is not limited to: differentiate between persistent and transient data; determine when to use isolated storage; plan for size limitations of isolated storage; design cloud-based storage
  • Plan for bandwidth limitations and implement network connectivity detection.
    • This objective may include but is not limited to: plan for disconnected scenarios; plan for low network bandwidth

Ссылки:

Designing Data Access Strategies (19%)

RU Links: Video (EN):

Экзамен 70-599: Pro: Designing and Developing Windows Phone 7 Applications, Часть 0

Итак приступаем к подготовке к экзамену по Windows Phone 7.

Пока анонсирована только Beta версия, но к релизу экзамена, обычно, ничего не меняется.

Страница экзамена: тут.

Требования к знаниям:

Designing Data Access Strategies (19%)

  • Send and receive data.
  • Design a data storage strategy.
  • Plan for bandwidth limitations and implement network connectivity detection.

Designing and Implementing Notification Strategies (17%)

  • Plan for and implement push notifications in the application.
  • Plan for and implement push notifications on the server.
  • Create and update live tiles.

Working with Platform APIs, Tasks, and Choosers (21%)

  • Design and implement sensor interaction.
  • Plan for and implement the use of Tasks and Choosers.
  • Plan for and implement multitouch and gestures.
  • Design and implement application navigation.

Designing the Application Architecture (21%)

  • Design for threading.
  • Monitor and tune performance.
  • Manage the application life cycle.
  • Prepare the application to meet Windows Phone 7 marketplace requirements.

Designing the User Interface and User Experience (23%)

  • Design for separation of concerns.
  • Design Windows Phone 7 control usage.
  • Recommend keyboard layout for a given situation.
  • Design for system themes, accent color, and screen orientation.

Основные ссылки: