Лучшие аудиокниги всех времен. Новые аудиокниги. У великой реки

Когда платформа Windows Presentation Foundation (WPF) впервые появилась в поле зрения.NET, большинство статей и демонстрационных приложений превозносили ее первоклассный механизм визуализации и возможности работы с трехмерной графикой. Хотя читать их и баловаться с ними интересно, такие примеры не отражают широких реальных возможностей WPF. Большинству из нас не нужно создавать приложения с вращающимися видеокубами, которые взрываются фейерверком, если их щелкнуть. Большинство из нас зарабатывают на жизнь, создавая программное обеспечение для отображения и правки больших объемов сложных научных или деловых данных.

Хорошие новости состоят в том, что WPF предлагает отличную поддержку для управления отображением и правкой сложных данных. В номере журнала MSDN® Magazine за декабрь 2007 года Джон Папа (John Papa) написал статью «Привязка данных в WPF» (msdn.microsoft.com/magazine/cc163299), отлично объясняющую ключевые концепции привязки данных в WPF. Здесь я рассмотрю более сложные случаи привязки данных, отталкиваясь от того, что Джон представил в вышеупомянутом выпуске рубрики «Точки данных». По прочтении читатели будут осведомлены о различных путях реализации распространенных требований к привязке данных, наблюдаемых в большинстве бизнес-приложений.

Привязка в коде

Одним из крупнейших изменений, представляемых WPF для разработчиков настольных приложений, является широкое использование и поддержка декларативного программирования. Интерфейсы пользователя и ресурсы WPF можно объявлять с помощью расширяемого языка разметки приложений (XAML), стандартного языка разметки, основанного на XML. Большинство объяснений привязки данных WPF показывают, лишь как работать с привязками в XAML. Поскольку всего, что можно сделать в XAML, также можно достичь в коде, важно, чтобы профессиональные разработчики под WPF знали, как работать с привязкой данных не только декларативно, но и программно.

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

Элементы WPF наследуют методы SetBinding и GetBindingExpression либо от FrameworkElement, либо от FrameworkContentElement. Это просто повышающие удобство работы методы, которые вызывают методы с теми же именами в служебном классе BindingOperations. В приведенном ниже коде показано, как использовать класс BindingOperations для привязки свойства Text текстового окна к свойству на другом объекте:

Static void BindText(TextBox textBox, string property)
{
if (!BindingOperations.IsDataBound(textBox, textProp))
{
Binding b = new Binding(property);
BindingOperations.SetBinding(textBox, textProp, b);
}
}

Привязку свойства несложно отменить, использовав следующий код:

Static void UnbindText(TextBox textBox)
{
DependencyProperty textProp = TextBox.TextProperty;
if (BindingOperations.IsDataBound(textBox, textProp))
{
BindingOperations.ClearBinding(textBox, textProp);
}
}

При очистке привязки привязанное значение также удаляется из целевого свойства.

Объявление привязки данных в XAML скрывает некоторые из лежащих в основе деталей. При начале работы с привязками в коде эти детали начинают всплывать на поверхность. Одна из них заключается в том, что отношения между источником привязки и ее целью на деле поддерживаются экземпляром класса BindingExpression, а не самим классом Binding. Класс Binding («Привязка») содержит высокоуровневую информацию, которую могут совместно использовать несколько классов BindingExpression, но обеспечение связи между двумя связанными свойствами производится лежащим в основе выражением. Нижеследующий код показывает, как BindingExpression можно использовать, чтобы программно удостовериться в том, проверяется ли свойство Text («Текст») текстового окна:

static bool IsTextValidated(TextBox textBox)
{
DependencyProperty textProp = TextBox.TextProperty;

var expr = textBox.GetBindingExpression(textProp);
if (expr == null)
return false;

Binding b = expr.ParentBinding;
return b.ValidationRules.Any();
}

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

Работа с шаблонами

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

Класс System.Windows.DataTemplate - лишь одна из форм шаблона в WPF. В целом, шаблон - это формочка для выпечки печенья, которую инфраструктура WPF использует, чтобы создавать визуальные элементы, помогающие в визуализации объектов, не имеющих собственного визуального представления. Когда элемент пытается отобразить объект, не имеющий такого представления, скажем, нестандартный бизнес-объект, можно указать элементу, как визуализировать объект, дав ему DataTemplate.
DataTemplate может создать столько визуальных элементов, сколько необходимо для отображения объекта данных. Эти элементы используют привязки данных для отображения значении свойств объекта данных. Если элементу неизвестно, как отображать объект, который ему указано визуализировать, он просто вызывает метод ToString на нем и отображает результаты в TextBlock.

Предположим, что у нас имеется простой класс, именуемый FullName, в котором хранится имя некоего лица. Необходимо отобразить список имен, в котором фамилия каждого лица выделялась бы по сравнению с прочим. Чтобы сделать это, можно создать шаблон DataTemplate, описывающий, как визуализовать объект FullName. Код, показанный наРис. 1, отображает класс FullName и фоновый код для окна, в котором отобразится список имен.

Рис. 1. Отображение объектов FullName с помощью DataTemplate

public class FullName
{
public string FirstName { get; set; }
public char MiddleInitial { get; set; }
public string LastName { get; set; }
}

public partial class WorkingWithTemplates: Window
{
// This is the Window"s constructor.
public WorkingWithTemplates()
{
InitializeComponent();

base.DataContext = new FullName
{
new FullName
{
FirstName = "Johann",
MiddleInitial = "S",
LastName = "Bach"
},
new FullName
{
FirstName = "Gustav",
MiddleInitial = " ",
LastName = "Mahler"
},
new FullName
{
FirstName = "Alfred",
MiddleInitial = "G",
LastName = "Schnittke"
}
};
}
}

Как можно увидеть наРис. 2, в файле XAML окна имеется элемент управления ItemsControl. Он создает простой список элементов, которые пользователь не может выбирать или удалять. У элемента ItemsControl имеется наблон DataTemplate, присвоенный его свойству ItemTemplate, с помощью которого он визуализирует каждый экземпляр FullName, созданный в конструкторе окна. Можно заметить, что у большинства элементов TextBlock в DataTemplate свойство Text («Текст») привязано к представляемым ими свойствам объекта FullName.

Рис. 2. Отображение объектов FullName с помощью DataTemplate














При запуске этого демонстрационного приложения оно выглядит, как показано наРис. 3. Использование DataTemplate для визуализации имени позволяет легко выделить фамилию каждого лица, поскольку параметр шрифта FontWeight соответствующего TextBlock является полужирным. Этот простой пример демонстрирует суть взаимоотношений между привязкой данных WPF и шаблонами. По мере углубления в тему я буду совмещать эти функции, создавая способы визуализации сложных объектов со все более широкими возможностями.

Рис. 3. Объекты FullName, визуализованные DataTemplate

Работа с унаследованным DataContext

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

Для ссылки на объект источника данных не обязательно устанавливать свойство DataContext. Если свойству DataContext элемента-предка в дереве элементов (технически говоря, логическом дереве) дано значение для его DataContext, то значение автоматически будет унаследовано каждым производным элементом в интерфейсе пользователя. Другими словами, если DataContext установлен так, чтобы ссылаться на объект Foo, то, по умолчанию, DataContext каждого элемента в окне будет ссылаться на тот же объект Foo. Любому элементу в окне можно легко дать свое значение DataContext, что заставит все элементы, производные от этого элемента, унаследовать новое значение DataContext. Это напоминает внешнее свойство в Windows Forms.

В предыдущем разделе я рассмотрел использование DataTemplates для создания визуализаций объектов данных. Свойства элементов, созданных шаблоном наРис. 2, привязаны к свойствам объекта FullName. Эти элементы неявно привязывают к их свойству DataContext. Свойство DataContext элементов, созданных ншаблоном DataTemplate, ссылается на объект данных, для которого используется шаблон, такой как объект FullName.

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

Другими примером унаследованного свойства зависимости является имеющееся у всех элементов свойство Font-Size. Если установить свойство зависимости FontSize на окне, то по умолчанию все элементы в этом окне будут изображаться текстом в указанном им размере шрифта. Инфраструктура, что используется для распространения значения FontSize вниз по дереву элементов, распространяет и DataContext.

Здесь термин «наследование» используется в значении, отличающемся от его объектно-ориентированного смысла, где подкласс наследует члены родительского класса. Наследование значений свойств относится только к распространению значений вниз по дереву элементов во время выполнения. Естественно, класс может унаследовать свойство зависимости для поддержки наследования значений в объектно-ориентированном смысле.

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

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

На представление коллекции возложено несколько задач. Оно отслеживает текущий элемент в коллекции, каковым обычно является выбранный/активный элемент в элементе управления «список». Представления коллекций также предлагают общие способы упорядочения, фильтрации и разбиения на группы элементов в списке. Несколько элементов управления могут привязывать к одному и тому же представлению вокруг коллекции, обеспечивая свою координацию друг с другом. В приведенном ниже коде показаны некоторые возможности ICollectionView:

// Get the default view wrapped around the list of Customers.
ICollectionView view = CollectionViewSource.GetDefaultView(allCustomers);

// Get the Customer selected in the UI.
Customer selectedCustomer = view.CurrentItem as Customer;

// Set the selected Customer in the UI.
view.MoveCurrentTo(someOtherCustomer);

У всех элементов управления типа списка, в том числе у списка, поля со списком и представления списка, свойство IsSynchronizedWithCurrentItem должно быть установлено на true для сохранения синхронизации со свойством представления коллекции CurrentItem. Это свойство определяет абстрактный класс Selector («Селектор»). Если оно не установлено на true, то выбор элемента в списочном элементе управления не обновит CurrentItem представления коллекции, и присваивание CurrentItem нового значения не будет отображено в списочном элементе управления.

Работа с иерархическими данными

Реальный мир полон иерархических данных. Клиент размещает несколько заказов, молекула состоит из множества атомов, отдел состоит из множества сотрудников, а солнечная система содержит группу небесных тел. Читатели, без сомнения, знакомы с такой схемой «основной/подробности».
WPF предоставляет различные способы работы с иерархическими структурами данных, каждый из которых подходит для своих ситуаций. По сути, альтернатива сводится либо к использованию нескольких элементов управления для отображения данных, либо к отображение нескольких уровней иерархии данных в одном элементе управления. Здесь я разберу оба эти подхода.

Использование нескольких элементов управления для отображения данных XML

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

На Рис. 4, основанном на описанной выше ситуации, показан упрощенный пример данных, с которыми может работать приложение, обернутых в компонент XmlDataProvider платформы WPF. Эти данные согут отображаться в интерфейсе пользователя, подобном показанному наРис. 5. Обратите внимание, что клиентов и заказы можно выбирать, но сведения о заказе существуют в форме списка только для чтения. Этому есть причина - возможность выбирать визуальный объект следует предоставлять только тогда, когда он воздействует на состояние приложения или является изменяемым.

Рис. 4. Иерархия клиентов заказов и сведений о заказах в формате XML





















Рис. 5 Один из способов отображения данных XML

В коде XAML наРис. 6 описано, как использовать эти различные элементы управления для отображения только что показанных иерархических данных. Это окно не требует кода; оно существует полностью в коде XAML.

Рис. 6. Код XAML для привязки иерархических данных XML к интерфейсу пользователя

"{Binding Source={StaticResource xmlData},
XPath=customers/customer}"
Margin="4"
>







ItemsSource="{Binding}"
>









x:Name="orderSelector"
DataContext="{Binding Path=CurrentItem}"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding XPath=order}"
>








Text="Order Details" />
DataContext=
"{Binding ElementName=orderSelector, Path=SelectedItem}"
ItemsSource="{Binding XPath=orderDetail}">



Product:

(

)





Обратите внимание на широкое использование коротких запросов XPath для указания платформе WPF на место, где нужно получить привязанные значения. Класс Binding предоставляет свойство XPath, которому можно выделить любой запрос XPath, поддерживаемый методом XmlNode.SelectNodes. Внутренние механизмы WPF используют этот метод для исполнения запросов XPath. Увы, это значит, что поскольку XmlNode.SelectNodes не поддерживает на данный момент использование функций XPath, их не поддерживает и привязка данных WPF.

Поле со списком клиентов и список заказов производят привязку к получающемуся набору узлов запроса XPath, выполняемого запросом DataContext корневого элемента Grid (таблица). DataContext списка автоматически возвратит CurrentItem представления коллекции, являющегося оберткой для коллекции XmlNodes, создаваемой для DataContext таблицы. Другими словами, DataContext списка - это выбранный в настоящий момент клиент. Поскольку ItemsSource списка неявно привязан к собственному DataContext (потому что не было указано другого источника) и его привязка ItemsSource исполняет запрос XPath для получения элементов из DataContext, то ItemsSource фактически привязан к списку заказов выбранного клиента.

Помните, что при привязке к данным XML реально привязка происходит к объектам, созданным вызовом к XmlNode.SelectNodes. При неосторожности можно получить несколько элементов управления, выполняющих привязку к логически эквивалентным, но физически различным наборам XmlNodes. Это обусловлено тем, что при каждом вызове к XmlNode.SelectNodes создается новый набор узлов XmlNode, даже если каждый раз передавать тот же запрос XPath тому же узлу XmlNode. Это особая проблема привязки к данным XML, так что при привязке к бизнес-объектам ее можно спокойно игнорировать.

Использование множества элементов управления для отображения бизнес-объектов

Теперь предположим, что требуется провести привязку к данным из предыдущего примера, но данные существуют в виде бизнес-объектов, а не в коде XML. Как это изменит способ привязки к различным уровням иерархии данных? Насколько похожим или отличающимся будет прием?

В коде наРис. 7 показаны простые классы, используемые для создания бизнес-объектов, сохраняющих данные, к которым произойдет привязка. Эти классы формируют ту же логическую схему, что и данные XML, использованные в предыдущем разделе.

Рис. 7. Классы для создания иерархии бизнес-объектов

public class Customer
{
public string Name { get; set; }
public List Orders { get; set; }


{
return this.Name;
}
}

public class Order
{
public string Desc { get; set; }
public List OrderDetails { get; set; }

public override string ToString()
{
return this.Desc;
}
}

public class OrderDetail
{
public string Product { get; set; }
public int Quantity { get; set; }
}

Код XAML окна, отображающего эти объекты, показан наРис. 8. Он очень похож на код XAML сРис. 6, но между существуют важные отличия, на которые стоит обратить внимание. Чего в коде XAML не наблюдается, так это конструктора окна, создающего объекты данных и устанавливающего DataContext, вместо установки кодом XAML ссылки на него, как на ресурс. Обратите внимание, что ни в одном из элементов управления свойство DataContext не установлено прямо. Все они наследуют то же свойство DataContext, являющееся экземпляром List.

Рис. 8. Код XAML для привязки иерархических бизнес-объектов к интерфейсу пользователя








/>
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=.}"
/>




IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=CurrentItem.Orders}"
/>



Text="Order Details" />
ItemsSource="{Binding Path=CurrentItem.Orders.CurrentItem.
OrderDetails}"
>



Product:

(

)





Другим существенным различием при привязке к бизнес-объектам вместо кода XML является то, что элементу ItemsControl, размещающему сведения о заказе, не нужно проводить привязку к SelectedItem списка заказа. Этот подход был необходим в случае привязки XML по причине отсутствия универсального способа сослаться на текущий элемент списка, элементы которого происходят из локального запроса XPath.

При привязке к бизнес-объектам вместо XML привязка ко вложенным уровням выбранных элементов является тривиальной задачей. Принадлежащая элементу ItemsControl привязка ItemsSource использует эту удобную функцию, дважды указывая CurrentItem в пути привязки: один раз для выбранного клиента, второй раз для выбранного заказа. Свойство CurrentItem является членом базового представления ICollectionView, являющегося оберткой источника данных, как уже говорилось выше.

Существует еще один интересный момент, относящийся к различию в подходах к работе XML и бизнес-объекта. Поскольку пример XML привязывает к XmlElements, необходимо предоставить шаблоны DataTemplate, чтобы объяснить, как визуализировать клиентов и заказы. При привязке к специальным бизнес-объектам можно избежать этого лишнего труда, просто переопределив метод ToString классов Customer («Клиент») и Order («Заказ») и позволив WPF отобразить выходные данные этого метода для данных объектов. Этого фокуса достаточно лишь для объектов, у которых могут быть простые текстовые представления. При работе со сложными объектами данных использование этой удобного приема может не иметь смысла.

Один элемент управления для отображения всей иерархии

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

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

В приведеном ниже коде XAML показано, как можно добавлять элементы TreeViewItem к представлению TreeView в коде XAML:







Прием создания элементов в TreeView вручную имеет смысл в ситуациях, когда элемент управления всегда будет отображать небольшой и статичный набор элементов. При необходимости отображать большие объемы данных, которые могут меняться со временем, становится необходимым использование более динамического подхода. На этом этапе вариантов есть два. Можно написать код, который проходит по структуре данных, создает элементы TreeViewItem, основанные на найденных им объектах данных, и добавляет эти элементы к TreeView. В качестве альтернативы можно воспользоваться иерархическими шаблонами данных и возложить всю работу на WPF.

Использование иерархических шаблонов данных

То, как WPF следует визуализировать иерархические данные через иерархические шаблоны данных, можно выразить декларативно. Класс HierarchicalDataTemplate является средством, наводящим мост между сложной структурой данных и визуальным представлением этих данных. Он очень похож на нормальный DataTemplate, но также позволяет указать, откуда происходят дочерние элементы объекта данных. Также можно предоставить классу HierarchicalDataTemplate шаблон для визуализации этих дочерних элементов.

Предположим, что теперь требуется отобразить данные, представленные наРис. 7 внутри одного элемента управления TreeView. Получившийся TreeView может выглядеть примерно так, как показано наРис. 9. Реализация этого включает использование двух HierarchicalDataTemplate и одного DataTemplate.

Рис. 9. Изображение целой иерархии данных в TreeView

Два иерархических шаблона отображают объекты Customer и Order. Поскольку у объектов OrderDetail нет дочерних элементов, их можно визуализировать с помощью неиерархического DataTemplate. Свойство ItemTemplate элемента TreeView использует шаблон для объектов типа Customer, поскольку объекты типа Customer и объекты данных содержатся в корневом уровне TreeView. В коде XAML, приведенном наРис. 10, показано, как собираются все части этой головоломки.

Рис. 10. Код XAML в основе отображения TreeView




xmlns:local="clr-namespace:VariousBindingExamples"
ObjectType="{x:Type local:Customer}"
MethodName="CreateCustomers"
/>





Product:

(

)


x:Key="OrderTemplate"
ItemsSource="{Binding Path=OrderDetails}"
ItemTemplate="{StaticResource OrderDetailTemplate}"
>


x:Key="CustomerTemplate"
ItemsSource="{Binding Path=Orders}"
ItemTemplate="{StaticResource OrderTemplate}"
>


ItemsSource="{Binding Path=.}"
ItemTemplate="{StaticResource CustomerTemplate}"
/>

Я выделяю коллекцию объектов Customer для DataContext таблицы (Grid), которая содержит представление TreeView. В коде XAML это можно проделать, используя ObjectDataProvider, являющийся удобным способом вызова метода из XAML. Поскольку DataContext наследуется вниз по дереву элементов, DataContext представления TreeView дает ссылку на этот набор объектов Customer. Именно по этой причине мы можем дать его свойству ItemsSource привязку "{Binding Path=.}", которая является способом указать, что свойство ItemsSource привязано к DataContext элемента TreeView.

Если свойству ItemTemplate представления TreeView не было присвоено значение, то TreeView будет отображать только объекты Customer верхнего уровня. Поскольку WPF не известно, как визуализировать Customer, оно вызовет ToString на каждом Customer и отобразит этот текст для каждого элемента. У него не будет возможности выяснить, что у каждого Customer имеется список связанных с ним объектов Order, а у каждого объекта Order список объектов OrderDetail. Поскольку платформа WPF не может волшебным образом разобраться в существующей схеме данных, необходимо объяснить эту схему платформе WPF, чтобы она могла правильно визуализировать структуру данных.

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

Важно обратить внимание на порядок объявления шаблонов. Шаблон необходимо объявить, прежде чем на него можно ссылаться через выражение StaticResource. Это требование, навязываемое средством чтения XAML, и оно относится ко всем ресурсам, а не только к шаблонам.

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

Работа со вводимыми пользователем данными

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

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

Проверка ввода через ValidationRules

В первой версии платформы WPF, являвшейся частью Microsoft® .NET Framework 3.0, имелась лишь ограниченная поддержка проверки ввода. У класса Binding имелось свойство ValidationRules, в котором могло храниться любое число классов, производных от ValidationRule. Каждое из этих правил могло содержать некоторую логику, проверяющую, является ли привязанное значение допустимым.

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

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

Public class Era
{

}

Если необходимо позволить пользователю изменять дату начала и продолжительность эпохи, можно использовать два элемента управления «текстовое поле» и привязать их свойства Text к свойствам экземпляра Era. Поскольку пользователь может вводить в текстовое поле всё, что пожелает, нельзя быть уверенным, что введенный текст окажется преобразуемым в экземпляр DateTime или TimeSpan. В данном случае можно использовать ExceptionValidationRule для сообщения об ошибках в преобразовании данных и затем отобразить эти ошибки в интерфейсе пользователя. В коде XAML, приведенном наРис. 11, показано, как можно выполнить эту задачу.

Рис. 11. Простой класс, представляющий эпоху времени


Start Date:









Duration:
Grid.Row="3"
Text="{Binding
Path=Duration,

/>

Эти два текстовых поля демонстрируют два способа, которыми ExceptionValidationRule можно добавить к свойству ValidationRules привязки в XAML. В текстовом поле Start Date («Дата начала») использован развернутый синтаксис элемента свойства, чтобы прямо добавить правило. В текстовом поле Duration («Продолжительность») использован сокращенный синтаксис, который просто устанавливает свойство привязки ValidatesOnExceptions на true. У обеих привязок свойство UpdateSourceTrigger установлено на PropertyChanged, чтобы ввод проверялся каждый раз, когда свойству текстового поля Text дается новое значение, вместо ожидания момента, когда элемент управления потеряет фокус. Снимок экрана программы показан наРис. 12.

Рис. 12. ExceptionValidationRule отображает ошибки проверки

Отображение ошибок проверки

Как показано наРис. 13, текстовое поле Duration содержит неверное значение. Содержащаяся в нем строка не преобразуема в экземпляр TimeSpan. Во всплывающем сообщении текстового поля отображается сообщение об ошибке, и маленький красный значок ошибки появляется на правой стороне элемента управления. Это поведение не является автоматическим, но его легко реализовать и подогнать под конкретный случай.

Рис. 13. Визуализация ошибок, выявленных при проверке ввода, для пользователя




DockPanel.Dock="Right"
Margin="2,0"
ToolTip="Contains invalid data"
Width="10" Height="10"
>











Статический класс Validation формирует взаимоотношения между элементом управления и любыми содержащимися в нем ошибками проверки путем использования прикрепленных свойств и статических методов. На эти прикрепленные свойства можно сослаться в XAML, чтобы создать состоящие из одной разметки описания того, как интерфейс пользователя должен представлять пользователю ошибки, выявленные при проверке ввода. Код XAML наРис. 13 отвечает за объяснение того, как визуализировать сообщения об ошибках ввода для двух элементов управления текстовых полей из предыдущего примера.

Style («Стиль») на Рис. 13 нацелен на все экземпляры текстового поля в интерфейсе пользователя Он применяет к текстовому полю три параметра. Первый, Setter («Метод установки») влияет на свойство Margin («Поля») текстового поля. Свойство Margin устанавливается на значение, которое предоставляет достаточно пространства для отображения значка ошибки с правой стороны.

Следующее свойство Setter в Style присваивает ControlTemplate, используемый для визуализации текстового поля, когда то содержит неверные данные. Оно устанавливает присоединенное свойство Validation.ErrorTemplate на шаблон ControlTemplate, объявленный над Style. Когда класс Validation («Проверка») сообщает, что проверка выявила в текстовом поле одну или несколько ошибок, текстовое поле визуализирует сообщение с помощью этого шаблона. Именно это создает красный значок ошибки, показанный на Рис. 12.

Style также содержит Trigger («Триггер»), отслеживающий прикрепленное к текстовому полю свойство Validation.HasError. Когда класс Validation устанавливает прикрепленное свойство HasError на true для определенного текстового поля, Trigger в Style активируется и присваивает текстовому полю всплывающее сообщение. Содержимое всплывающего сообщения привязано к сообщению об ошибке исключения, выданного при попытке преобразовать текст из текстового поля в экземпляр типа данных свойства источника данных.

Проверка ввода через IDataErrorInfo

С появлением Microsoft .NET Framework 3.5 поддержка проверки ввода в WPF радикально улучшилась. Подход ValidationRule полезен для простых приложений, но реальные приложения имеют дело со всей сложностью реальных данных и бизнес-правил. Кодирование бизнес-правил в объекты ValidationRule не только привязывает этот код к платформе WPF, но также и не позволяет бизнес-логике быть там, где ей и положено быть: в бизнес-объектах!

У многих приложений имеется бизнес-слой, где все сложности обработки бизнес-правил заключены в набор бизнес-объектов. При компиляции в Microsoft .NET Framework 3.5 можно воспользоваться интерфейсом IDataErrorInfo, чтобы заставить WPF запрашивать бизнес-объекты о том, находятся ли они в допустимом состоянии или нет. Это избавляет от необходимости размещать бизнес-логику в объектах, отдельных от бизнес-слоя, и позволяет создавать бизнес-объекты, независимые от платформы интерфейса пользователя. Поскольку интерфейс IDataErrorInfo используется уже несколько лет, это также упрощает повторное использование бизнес-объектов из старых приложений Windows Forms или ASP.NET.

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

Эти типы правил подобны общей идее бизнес-логики в том, что оба они являются экземплярами правил области. Правила области лучше всего создавать в объектах, которые сохраняют их состояние: объектах области. В коде, приведенном наРис. 14, показан класс SmartEra, предоставляющий сообщения о выявленных проверкой ошибках через интерфейс IDataErrorInfo.

Рис. 14. IDataErrorInfo предоставляет сообщения о выявленных проверкой ошибках

public class SmartEra
: System.ComponentModel.IDataErrorInfo
{
public DateTime StartDate { get; set; }
public TimeSpan Duration { get; set; }

#region IDataErrorInfo Members

public string Error
{
get { return null; }
}

public string this
{
get
{
string msg = null;
switch (property)
{
case "StartDate":
if (DateTime.Now < this.StartDate)
msg = "Start date must be in the past.";
break;

case "Duration":
if (this.Duration.Ticks == 0)
msg = "An era must have a duration.";
break;

default:
throw new ArgumentException(
"Unrecognized property: " + property);
}
return msg;
}
}

#endregion // IDataErrorInfo Members
}

Употребить поддержку проверки класса SmartEra из интерфейса пользователя WPF очень просто. Нужно лишь указать привязкам, что тем следует принять интерфейс IDataErrorInfo на объекте, к которому они привязаны. Это можно сделать одним из двух способов, как показано наРис. 15.

Рис. 15. Употребление логики проверки


Start Date:










Duration:
Grid.Row="3"
Text="{Binding
Path=Duration,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True}"
/>

Подобно тому, как правило ExceptionValidationRule можно добавить к коллекции ValidationRules привязки явно или неявно, правило DataErrorValidationRule можно добавить прямо к ValidationRules привязки, или же можно установить свойство ValidatesOnDataErrors на true. Оба подхода дают один и тот же конечный эффект - система привязки запрашивает интерфейс IDataErrorInfo источника данных на предмет выявленных проверкой ошибок.

Подводя итоги

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

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

Привязка данных в XAML

Совместное использование объектов в файле XAML также может осуществляться через привязку данных. По сути привязка данных (data binding) связывает между собой два свойства разных объектов. Как будет показано позже, привязки данных чаще всего применяются для связывания визуальных элементов страницы с источниками данных; кроме того, они являются важной составляющей реализации популярного архитектурного паттерна MVVM (Model-View-ViewModel) . Привязки также играют важную роль при определении шаблонов отображения объектов данных.

Привязки данных могут использоваться для связывания свойств двух элементов. Элемент Binding , как и StaticResource, обычно выражается в виде расширения разметки, то есть заключается в фигурные скобки. Однако элемент Binding также допускает альтернативное выражение в виде синтаксиса элементов свойств.

Используйте следующий словарь ресурсов в нашем тестовом проекте:

Настройки кистей

Неявный стиль TextBlock не содержит свойства Foreground. Кисть LinearGradientBrush определяется для первого из четырех элементов TextBlock, использующих эту кисть, а последующие элементы TextBlock ссылаются на эту же кисть через привязку:

У привязки данных имеется источник (source) и приемник (target) . Приемником всегда является свойство, для которого устанавливается привязка, а источником - свойство, к которому оно привязывается. Источником приведенных привязок является элемент TextBlock с именем topTxb; приемниками - три элемента TextBlock, совместно использующих свойство Foreground. Два приемника представляют более стандартный способ выражения объекта Binding как расширения разметки XAML:

{Binding ElementName=topTxb, Path=Foreground}

Расширения разметки XAML всегда размещаются в фигурных скобках. В расширении разметки для Binding обычно необходимо задать пару свойств, разделяемых запятыми. Свойство ElementName обозначает имя элемента, для которого задано желаемое свойство; свойство Path предоставляет имя свойства.

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

Последний элемент TextBlock демонстрирует выражение Binding в менее распространенном синтаксисе элементов свойств:

В этом синтаксисе кавычки вокруг значений свойств обязательны, т.к. это обычные атрибуты XML. Вы также можете создать объект Binding в коде и назначить его приемному свойству методом SetBinding() , определенным в FrameworkElement. При этом выясняется, что приемник привязки всегда должен быть свойством зависимости.

Свойство Path класса Binding называется так потому, что оно может содержать несколько имен свойств, разделенных точками. Например, попробуйте заменить одно из значений Text в проекте следующим значением:

Text="{Binding ElementName=topTxb, Path=FontFamily.Source}"

Первая часть Path указывает, что нам нужны данные из свойства FontFamily. Свойству задается объект типа FontFamily, содержащий с именем Source, обозначающим название семейства шрифта. Следовательно, в TextBlock будет выведен текст «Arial».

Попробуйте применить следующую конструкцию к любому элементу TextBlock в нашем проекте:

Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize}"

Здесь расширение разметки RelativeSource находится внутри расширения разметки Binding и используется для ссылки на свойство того элемента, для которого задается привязка.

Что объединяет бизнесмена за рулем авто, студента в утреннем метро и домохозяйку за уборкой? Ответ прост - возможность читать книгу. Сегодня даже для самого занятого человека это доступно и просто: слушать любимое произведение в аудио-формате. Кроме гарнитуры или колонок понадобится, конечно, сама книга. Представленный в статье рейтинг лучших аудиокниг поможет разобраться во всем их многообразии. Здесь описаны жанры, названия и имена тех, благодаря кому произведение оживает.

Лучшие аудиокниги: рейтинг "Фантастика"

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

  1. Произведения братьев Стругацких "Обитаемый остров", "Понедельник начинается в субботу", "Трудно быть Богом" и другие занимают лидирующие позиции в списке "Лучшие аудиокниги: рейтинг "Фантастика". Озвучены они Л. Ярмольником, А. Резалиным или М. Черняком. Но каждая из них - отдельная увлекательная история о вымышленном, но таком знакомом каждому мире.
  2. Вторую позицию по праву заслужили аудиокниги в авторстве Макса Фрая: "Дебют в Эхо", "Чужак", "Гнезда химер". Озвучка Д. Верового отлично передает атмосферу детектива, фантастики, иллюзий, непривычную иронию или жесткий юмор.
  3. Произведения С. Лукьяненка "Чистовик" и "Недотепа" в озвучке А. Андриенка - это легкая, увлекательная проза о вымышленном мире и одиноком герое, который сражается в нем и пишет свою историю.
  4. Фантастический мир, описанный в произведении Д. Глуховского "Метро 2033", сочетает в себе лучшие традиции жанра - вымышленные персонажи-монстры, спасение мира и современного героя. Озвучка принадлежит Е. Каменецкому.

Аудиокниги: современная проза

  1. "Цветы для Элджернона" Д. Киза - это душевная история, сочетающая в себе элементы психологии, фантастики и романтизма. Читается на одном дыхании, а в озвучке С. Янишевского по праву становится лидером рейтинга.
  2. Рейтинг лучших аудиокниг продолжает "Похороните меня за плинтусом" П. Санаева в собственной озвучке. Кто, как не автор, лучше передаст описанное - атмосферу советского детства глазами ребенка, любовь, предательство и мир в целом?
  3. "Бойцовский клуб" Ч. Паланика - культовое произведение, что в исполнении Д. Земцова приобретает особую окраску. Читать или слушать, но никому не рассказывать о бойцовском клубе!
  4. "Дом, в котором..." М. Петросян - магически реальная, художественная, но из настоящего мира, увлекательная книга в озвучке И. Князева.
  5. "Игра Престолов" Дж. Мартина потрясла мир не только литературным изложением, но и качественной экранизацией. Пришло время оценить произведение и в аудио-версии в исполнении Полонецких Дмитрия и Елены.

Классика: рейтинг аудиокниг

  1. "Мастер и Маргарита" - нестареющая книга М. Булгакова получила новую жизнь благодаря работе А. Клюквина, М. Суханова и Д. Мороз.
  2. Озвучка произведений отца и сына Дюма "Три мушкетера" и "Граф Монте-Кристо" В. Герасимовым приносит им почетное 2-е место.
  3. "Вечера на хуторе близ Диканьки" Гоголя ожили голосом А. Клюквина и продолжают радовать любителей жизнеутверждающих и добрых произведений.
  4. В мир настоящей дружбы, любви и человечности окунет исполнитель книги "Три товарища" Ремарка В. Антоник.
  5. "Моби Дик" Мелвилла стал еще более чарующим и увлекательным, благодаря голосу В. Гемасимова.
  6. "Преступление и наказание" Достоевского по праву оказывается в списке всех лучших книг. Не исключение - и аудио, которое также принадлежит В. Герасимову.

Обучающая и научная литература: рейтинг

Среди популярной литературы также есть лучшие аудиокниги. Рейтинг читателей в этом жанре можно представить так:

  1. "Богатый папа, бедный папа" Р. Кийосаки и Ш. Лектер - оригинальное руководство по взаимосвязи между материальным состоянием семьи и воспитанием детей.
  2. А. Карр, "Легкий способ бросить курить" - книга с названием, которое говорит само за себя. Отзывы читателей свидетельствуют, что способ, предложенный автором, действительно работает.
  3. "Подсознание может все" Дж. Кехо - популярная книга об активации работы мозга и самопрограммирования на счастливую жизнь.
  4. "Психология влияния" Р. Чалдини - это произведение не только для специалистов. Сборник эффективных практик, которые помогут оказывать влияние на людей и защититься от нежелательного внимания.
  5. "Как влюбить в себя любого" Л. Лендес - еще одного остроумное руководство с кричащим названием. Рассказывает о 6-и составляющих романтической любви.

Аудиокниги для детей

  1. "Маленький принц" Экзюпери заслуженно считают учебником добра и общечеловеческих ценностей. Книга обязательна к прочтению не только детям, но и взрослым, которые погрязли в насущных проблемах. Озвучка представлена К. Хабенским и М. Ефремовым.
  2. Цикл историй о Гарри Поттере - это сегодня целая культура. Джоан Роулинг и ее детище озвучены для формата аудио-книги талантливым исполнителем А. Клюквиным.
  3. Детскую литературу невозможно представить без Тома Сойера и его заядлого товарища Гека Финна. Пропустить в мир мальчишеских приключений героев Марка Твена может исполнитель книги А. Котов.
  4. Целый аудиоспектакль посвящен приключениям девочки Алисы в Стране чудес и Зазеркалье - сказочным мирам, созданным Л. Кэрроллом. Озвучены действия книги В. Абдуловым и Г. Ивановой, а также В. Бондаревым, М. Хворостовой и О. Долониной.

Лучшие исполнители аудиокниг: рейтинг

Качество аудиокниги зависит не столько от ее жанра, сколько от качества исполнения. Ведь первое означает исключительно личные литературные предпочтения человека, и здесь будет столько же мнений, сколько и людей. Аудиоформат предполагает же переобразование визуальной информации в аудиальную. Одна и та же книга будет абсолютно по-разному восприниматься, если ее прочитают вслух разные люди. Поэтому есть те, кому удается это лучше остальных. Тембр их голоса, интонация, эмоциональная включенность и дают возможность создать рейтинг лучших аудиокниг.

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

  1. Алексей Борзунов - голос таких известных произведений, как "Парфюмер", "Портрет Дориана Грея", "Белая гвардия", "Униженные и оскорбленные" и других книг, в которых важно передать трагичность и реализм жизни.
  2. Александр Клюквин. Ему принадлежит озвучка фундаментальных классических, как "Война и мир", "Ревизор", "Мастер и Маргарита", произведений, а также более современных - истории о Гарри Поттере. Голос этого человека знаком и любителям культового сериала про Альфа. Отличительная черта - это способность передать характер и настроение очень разных, непохожих друг на друга персонажей.
  3. Вячеслав Герасимов - диктор с 30-летним стажем, мастер интонации и автор озвучки многих культовых произведений классической и современной прозы: "Мертвые души", "Идиот", "Черные камни", "Колесо счастья" и многих других.
  4. Максим Пинскер - обладатель чарующего низкого тембра голоса, который подарил читателям возможность слышать такие классические произведения, как "Капитанская дочка", "Три товарища", "Лолита" и многие другие.
  5. Александ Котов - голос трагикомичных произведений, которому удалось озвучка историй о Томе Сойере, "Айвенго", "Собора Парижской Богоматери", "Красного и черного".
  6. Александр Бордуков, которому принадлежит голос персонажей из историй про Шерлока Холмса, "Госпожи Бовари", "Великого Гетсби".
  7. Иван Литвинов, талант к очень точной передаче характеров персонажей и атмосферы произведения. Его голосом прочтены любимые многими произведения Булгакова, Оруэлла, Кинга, Достоевского и многих других.
  8. Александр Хорлин - настоящий мастер в словесном изображении увлекательных путешествий, приключений и героев с нестандартным мышлением. Это и "Приключения Гулливера", и "Преступление и наказание", и "Повелитель мух", и "Коллекционер".
  9. Олег Булдаков - разноплановая личность, попробовавшая себя в качестве многих профессий, главным инструментом его является голос. Он прошел путь от диджея на радио до телеведущего и, конечно, исполнителя аудио-версий книг. Множество произведений Кинга, "Осиная фабрика", "Правда" - его лучшие аудиокниги.

Рейтинг произведений и озвучивших их людей можно дополнять. С каждым годом он может меняться. Неизменно одно - даже с развитием технологий количество читателей не меняется. Наоборот, прогресс дает возможность читать любимые произведения в тех условиях, которые для этого не предназначены. И такая тенденция не может не радовать.

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

Игра престолов

На первом месте у нас окажется цикл «Игра престолов». Книги Джорджа Мартина рассказывают о героях и лордах, магах, воинах и убийцах, странных существах, обращающих своих врагов в ужас и мечах из необыкновенного материала, способных поразить кого угодно. В этом сказании можно узнать много интересного, здесь идут рядом трагедия и предательство, интриги и кровопролитные сражения – это отличный образец современной литературы.

Москва-Петушки

На втором месте классическое произведение Венедикта Ерофеева «Москва-Петушки», посвященное путешествию алкоголика на электричке. Это впечатляющее произведение не просто так попало в наш рейтинг, лучшие чтецы аудиокниг могут позавидовать С. Шнурову, читающему его весьма эмоционально.

Люди, которые играют в игры

Жанр психологии также весьма востребован, современный читатель пытается разобраться в особенностях своего сознания с завидным упорством. «Люди, которые играют в игры» – книга Эрика Берна, известного американского психоаналитика. Этот человек – создатель теории трансакционного анализа.

Гарантийные человечки


Даже сказки попадают в наш рейтинг лучших аудиокниг. Как известно, на любой предмет имеется гарантия – то есть, он не должен выходить из строя. По мнению Эдуарда Успенского, за нее отвечают маленькие существа, которые прячутся в бытовых приборах. В его «Гарантийных человечках» в холодильнике живет Холодилин, а в пылесосе – Пылесосин, в радио же – персонаж, которого зовут Новости дня. Эта добрая история подарит детям массу приятных впечатлений.

У великой реки


Когда речь заходит о такой вещи, как рейтинг аудиокниг, фантастика в нем всегда присутствует на лидирующих позициях. В книге Андрея Круза «У великой реки» говорится о пересечении миров, где обычное и привычное нам столкнулось с магией и волшебством. В центре книги – история охотника на нечисть, столкнувшегося с серьезными проблемами.

Гарри Поттер


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

Цветы для Элджернона

Еще одно классическое произведение, автор которого – Дэниэл Киз. Трагичная история, главный герой которой – человек с задержками в развитии, который в результате экспериментов ученых становится сверхгением. Но эффект лекарства оказывается непостоянным – и умнейший человек на планете снова возвращается к своему предыдущему состоянию, успев лишь совсем ненадолго познать счастье. В исполнении Семена Янишевского рассказ становится особо интересным.

Шантарам

Заключает наш рейтинг аудиокниг «Шантарам» Грегори Дэвида Робертса. Читаемая Иваном Литвиновым, эта история о человеке, чья жизнь внезапно пошла под откос. Он совершает ограбления, попадает в тюрьму, бежит из нее, становится контрабандистом, встречает и теряет любовь – это весьма насыщенное событиями произведение, которое можно прослушать на одном дыхании. Никого не удивляет тот факт, что ей удалось в короткий срок попасть в списки бестселлеров и получить массу сравнений с лучшими произведениями авторов нового времени.

Представьте, что вторую мировую выиграли Германия и Япония. Они же и поделили мир между собой и своими союзниками. Фантазия Дика, имеет право на существование. А почему нет? Не только он размышляет над этой темой. В книге нет второстепенных персонажей, каждый из них важен. Они все звенья одной цепи. Дёрнешь одного, за ним последуют другие. Как такового описания мира нет. Мы узнаём лишь отрывкам...

Группа людей волей случая, оказываются вдали от мира в старинном особняке с не очень хорошей репутацией. Кстати, классической стала такая завязка, во многом благодаря, именно «Призраку дома на холме». И дом не заставляет постояльцев долго томится в ожидании – здесь вам и ночные шорохи и стуки, и зловещий смех, и могильны...

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

«Повинная голова» - роман, активно сопротивляющийся написанию рецензии. Ну о чём, правда, писать? О смешении ингредиентов? О всепронизывающем цинизме человечества в лице турагентов? О лживости всего, видимого глазами (помните совет закрыть глаза?)? О символах Земного рая и созвездия Пса? О протесте против Власти? Об отно...

Место действия - разные города и села только что обретшей независимость Нигерии, время - 1960-е гг. В центра внимания судьбы двух сестер-двойняшек Оланны и Кайнене. У них, казалось, было все для беззаботной жизни: деньги, известность, перспективы. Но первая связывает жизнь с преподавателем и сама начинает преподавать, а...

В 1962 году Саймак фактически описал будущую (через 30 лет) приватизацию России по Чубайсу (скупка!! а как же люди? да наплевать на них, главное скорее раздать). Вторжение инопланетян на Землю, причем попытка вторжения весьма необычна - пришельцы постепенно захватывают землю скупив ее. Главный герой, журналист Паркер Гр...

Ромен открывается здесь совершенно по-новому. Он пишет в 1967 году фантасмагоричный роман, фарс, целиком состоящий из аллюзий, символов. Ромен выписывает словами шизофрению - яркую, цветистую, галлюциногенную, бредовую. "Пляска Чингиз-Хаима" - это восхитительный бред, комедия, игра. Что делать, если вы - бывший исполните...

Едва ли не лучший сорокинский сборник рассказов. Великая и страшная симфония еды; гротескный мир, сочащийся едой и поглощающий сам себя. Ни один из рассказов не похож на остальные, и все они раскрывают сущность "едения" с какого-то нового ракурса. Конечно, Сорокин во многом верен себе по части эпатажа, и к "Пиру" зачасту...

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

В третьей книге цикла Юрия Слепухина читатель встречается только с одной знакомой героиней - Людмилой Земцовой, которую угнали в Германию как "восточную работницу" вскоре после оккупации Энска во второй книге. Они где-то там, в Советском Союзе, скорее всего, их положение более безопасно, чем положение Люды, которая продо...

Пролетели пять лет учёбы в средней школе. Татьяна и Сергей строят серьёзные планы на будущее. Вот только атмосфера в обществе становится всё напряжённее. Таня чувствует это. Кажется, будто все стоят на рубеже, на перекрёстке, и должно случиться что-то значимое. Но пока в жизни всё идёт своим чередом. В субботу, 21 июня,...

Да хранит Господь всех, кто в море, и всех, кто хочет в море, и всех, кто не хочет в море. Всё равно рано или поздно каждый придёт к нему. Вот такая короткая и странная молитва была у капитана красавицы-бригантины "Мечта". Содержать такое судно дело довольно-таки дорогое и капитан решает несколько раз в год брать на борт...

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

Гари родился в Российской империи в 1914 году, эмигрировал сначала в Польшу, потом во Францию, вырос без отца. Роман «Обещание на рассвете» целиком и полностью посвящен его матери – Мине Овчинской. И он не оставит вас равнодушным: вы либо полюбите эту книгу всем сердцем, либо почувствуете непреодолимое отторжение. Как пр...

Хорошая любовная история без какой-либо борьбы за власть, интриг и прочего. Просто книга о судьбе двух людей, оказавшихся вместе не по своей воле. Героиня приезжает из пансиона в дом виконта, за которого отдал ее замуж отец. И есть мужчина - с виду суровый, безразличный и очень злой. И вот этих двоих свел папенька этой с...

Ильф и Петров - эти фамилии известны чуть ли не каждому жителю нашей необъятной Родины. Но всё же, большинство их знает как авторов "12 стульев" и "Золотого телёнка". Некоторые ещё знакомы и с "Одноэтажной Америкой". Но вот книга "Необыкновенные истории из жизни города Колоколамска", к сожалению, известна очень узкому кр...