Настройка отображения данных с привязкой данных и WPF

ОГЛАВЛЕНИЕ

Когда платформа 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)
{
    DependencyProperty textProp = TextBox.TextProperty;
    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 неизвестно, что он проверяется, вопрос необходимо задать его родительнской привязке. Различные приемы проверки ввода я рассмотрю ниже.