Статическая проверка привязок

Или ", как вы убедитесь, что все ваши привязки остаются верными?"
(это довольно длинный, но неся со мной, я старался сделать это как можно короче)

Рассмотрим следующий пример:

    <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.

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