2010-07-04 4 views
6

Silverlight 4 вышел, и, похоже, мы снова пропустили функциональность DataTemplate DataType в этом выпуске, что довольно важно для поддержки MVVM IMHO. Для моих приложений WPF на данный момент я довольно привык к глобальному добавлению DataTemplates для своих просмотров в мое приложение. Ресурсы с DataTypes для моих соответствующих ViewModels:Silverlight 4 DataTemplate DataType

т.е.

<DataTemplate DataType="{x:Type viewModels:myViewModel}"> 
<views:myView/> 
</DataTemplate> 

Мне нравится этот подход, так как все мои связанные ViewModels автоматически отображать правильное содержание ... особенно полезно, когда у меня есть некоторые ItemSource на мой взгляд, связанным с коллекцией ViewModels ... Это, к примеру, будет автоматически убедитесь, что каждая вкладка в TabControl, связанная с Collection<SomeViewModel>, отображает представление, связанное с SomeViewModel.

Некоторые вещи, которые я пробовал для SL 3 включают:

  • Создание «DataTemplatePresenterContentControl», который автоматически применяет DataTemplate для Контента, когда элемент управления загружен

  • Использование TypeConverter, применяется динамически управляющая нагрузка, идущая вниз по визуальному дереву, ищущему объекты, привязанные к данным

  • Использование стиля, динамически применяемого при нагрузке на управление, g для объектов, связанных с данными

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

Итак, поскольку это все еще невозможно из коробки в Silverlight 4, я был бы признателен, если кто-нибудь еще придумает некоторые разумные альтернативы.

Спасибо.

ответ

8

Как мне сделать это в несколько коммерческих проектов заключается в следующем:

У меня есть стандартный IValueConverter

public class ViewTemplateChooser : IValueConverter 
{ 
    /// <summary> 
    /// Modifies the source data before passing it to the target for display in the UI. 
    /// </summary> 
    /// <returns> 
    /// The value to be passed to the target dependency property. 
    /// </returns> 
    /// <param name="value">The source data being passed to the target.</param><param name="targetType">The <see cref="T:System.Type"/> of data expected by the target dependency property.</param><param name="parameter">An optional parameter to be used in the converter logic.</param><param name="culture">The culture of the conversion.</param> 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is MyViewModel) 
     { 
      return new MyView { DataContext = value }; 
     } 

     return value; 
    } 

    /// <summary> 
    /// Modifies the target data before passing it to the source object. This method is called only in <see cref="F:System.Windows.Data.BindingMode.TwoWay"/> bindings. 
    /// </summary> 
    /// <returns> 
    /// The value to be passed to the source object. 
    /// </returns> 
    /// <param name="value">The target data being passed to the source.</param><param name="targetType">The <see cref="T:System.Type"/> of data expected by the source object.</param><param name="parameter">An optional parameter to be used in the converter logic.</param><param name="culture">The culture of the conversion.</param> 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Преобразователь будет требовать регистрацию имен

xmlns:Converters="clr-namespace:YourProject.Converters" 

Тогда вы ссылаетесь на преобразователь в своем разделе ресурсов:

<UserControl.Resources> 
    <Converters:ViewTemplateChooser x:Key="TemplateChooser" /> 
</UserControl.Resources> 

и, наконец, я использую конвертер для преобразования ViewModel в View с DataContext в целях набора на ViewModel

<ContentControl Content="{Binding Workspace, Converter={StaticResource TemplateChooser}}" Margin="5,35,5,5" Grid.Column="1" /> 

Преобразователь может быть модифицирован для реализации стратегии навигации, я попытался сделать пример как можно проще.

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

1

В WPF и Silverlight я использую Prism для этого. Я считаю, что это намного более универсально, чтобы отключать представления на основе типов. Это требует немного, чтобы заставить его привязаться, но как только он находится, возможности бесконечны.

Редактировать

Я делаю это путем связывания RegionName свойству в моем ViewModel (Может быть GetType(). Name, если вы хотите). Затем я регистрирую типы для имен, и он просто работает.

В случае что-то вроде ListBox, я создал шаблон данных, чтобы быть:

<ContentControl Regions:RegionManager.RegionName="{Binding SomeName}" /> 

Если вы не хотите SomeName быть на объекте, являются обязательными для, рассмотрите ValueConverter что возвращает название типа:

<ContentControl Regions:RegionManager.RegionName="{Binding SomeName, Converter={StaticResource ObjectToTypeConverter}}" /> 

Помогло ли это?

+0

Я тоже использую RegionManager Призма, но не могли бы вы подробнее рассказать о том, как вы это делаете? – Jeff

+0

Разработка в моем редактировании выше. –

+0

Да, спасибо. Мне нравится этот подход. Но он по-прежнему не касается одной проблемы, о которой я упоминал выше; привязка к IEnumerable - например, привязка TabControl к коллекции и ожидающая, что каждая вкладка отобразит MyViewForMyViewModelClass UserControl. Или есть способ адаптировать ваш подход к поддержке этого? Благодарю. – Jeff

Смежные вопросы