Статическая проверка привязок
Или ", как вы убедитесь, что все ваши привязки остаются верными?"
(это довольно длинный, но неся со мной, я старался сделать это как можно короче)
Рассмотрим следующий пример:
<TextBox Name="tb" />
<TextBlock Text="{Binding Text.TheProp, ElementName=tb}" />
Во время компиляции известно, что привязка неверна (т.е. синтаксический анализатор знает тип элемента tb
, и, следовательно, он знает тип его свойства Text
, и поэтому он знает, что TheProp
не существует).
Тем не менее, этот код будет компилироваться и выполняться (хотя с сообщением об ошибке привязки в отладочном выходе).
Такое поведение может оказаться очень полезным в некоторых ситуациях: независимо от того, какой именно тип данных есть, если у него есть соответствующие свойства, я в порядке. Таким образом, мы получаем вид "декларативной утиной печати".
Однако, утиная печать не всегда хорошая вещь.
В частности, при использовании шаблона MVVM я знаю (большую часть времени) точные типы всех объектов ViewModel. С другой стороны, модели становятся все более сложными с течением времени, и меня волнует будущий рефакторинг: что, если я решит переименовать некоторые свойства или, не дай бог, поместить их в отдельный агрегированный объект? Что произойдет со всеми моими привязками? Нужно ли мне рубить все файлы XAML? И даже без рефакторинга - что, если я просто сделаю опечатку?
Аналогичная проблема уже решена в других местах XAML. Если, например, вы поместили неправильное имя свойства в Style/Setter/@Property
, вы получите ошибку времени компиляции.
TemplateBinding
также обеспечивает такую проверку. Это очень удобно.
Итак, в идеале, мне бы хотелось увидеть что-то вроде этого:
ProductViewModel.cs:
public class ProductViewModel
{
public Name { get; set; }
public Price { get; set; }
}
ProductView.XAML:
<UserControl x:Class="Shopping.View.ProductView"
x:DataContextType="vm:ProductViewModel"
xmlns:vm="clr-namespace:Shopping.ViewModel"
... >
<TextBox Text="{Binding Name}" /> <!-- OK -->
<TextBox Text="{Binding Price}" /> <!-- OK -->
<TextBox Text="{Binding ABC}" /> <!-- Compile time error: there is no property ABC in ProductViewModel -->
</UserControl>
ShoppingCart.XAML:
<UserControl x:Class="Shopping.View.ShoppingCartView"
x:DataContextType="vm:ShoppingCartViewModel"
xmlns:vm="clr-namespace:Shopping.ViewModel"
... >
<ItemsControl ItemsSource="{Binding Products}"
ItemType="vm:ProductViewModel" > <!-- Static check happens here
ShoppingCartViewModel.Products must
implement IEnumerable<ProductViewModel> -->
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:ProductViewModel">
<view:ProductView /> <!-- DataContext is known to be of correct type
because of DataTemplate.DataType property -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
Но вернемся к реальности. На самом деле все, что мечтает, просто не произойдет в ближайшем будущем.
Однако я уверен, что я не первый человек, у которого есть эта проблема.
Итак, наконец, вопрос: Как вы убедитесь, что ваши привязки верны? И что они остаются такими?
Ответы
Ответ 1
Как насчет статического анализа вашего Xaml, выполняемого как шаг после сборки?
В рамках .Net 4 Microsoft выпустила новую библиотеку System.Xaml, чтобы обеспечить надежную поддержку синтаксического анализа и поддержки сериализации Xaml независимо от WPF. Теперь они начинают строить всевозможные интересные вещи, некоторые из которых могут помочь вам.
В XamlToolkit, например, вы найдете XamlDOM, который позволяет вам выполнять простой статический анализ файлов Xaml. И принимая это немного дальше, Правила FxCop для XAML.
Наиболее интересным является Rob Relyea BindingFinder, который имеет явную цель проверки типов Bindings в Xaml. Это требует, чтобы у вас были типы подсказок в вашем Xaml, например, атрибут DataType в DataTemplate или новый d: атрибут DataContext в ваших представлениях (которые Blend использует для предоставления данных времени разработки). Затем он использует XamlDOM, чтобы проверить, что все соответствует.
Обновление: Resharper 6 теперь предоставляет intellisense для привязок данных и предупреждения, если вы ошиблись в своих путях свойств.
Ответ 2
Как практический вопрос, я никогда не обнаружил, что это проблема, по крайней мере, при использовании шаблона MVVM. Модель просмотра существует только для поддержки представления. Я не собираюсь менять его, не меняя другого. Рефакторинг модели представления не приведет к нарушению привязок в представлении, потому что нет смысла реорганизовывать модель представления для себя. Вы будете реорганизовывать только модель представления, когда (и потому) вы меняете дизайн представления.
Другая причина, по которой у меня нет этой проблемы, заключается в том, что я не разрабатываю модель представления независимо от Expression Blend. Для всех, кроме самых тривиальных пользовательских интерфейсов, я строю свои модели взглядов с использованием какой-то инъекции зависимостей, чтобы создать тестовый источник данных, который можно использовать в Expression Blend. Когда я создаю привязки в Blend, я сразу знаю, правильно ли я сделал это.
Как и в случае с MVVM в целом, это невероятная боль в заднице, пока вы не поймете, что делаете и почему. (Этот длинный пост в блоге от Jonas Follesø дает неплохой обзор того, как использовать Ninject, хотя нет конца другим фреймворкам, которые вы можете использовать.) Я уверен, что есть проблемы, которые я еще не раскрыл с помощью этой методологии - выше и выше проблема в том, что я добавил рамки DI и Expression Blend в кучу вещей, которые мне нужно понять для разработки приложений WPF.
Пабло Казальс сказал, что постоянное экспериментирование держит художника молодым. Я не чувствую себя молодым.