2014-11-19 2 views
3

У меня есть 4 класса в моей модели ViewModel, которая реализует интерфейс IPage (интерфейс, который я создал). В ViewModel моего приложения у меня есть свойство CurrentPage типа IPage.Почему WPF не выбирает правильный DataTemplate в моем случае?

В слое «Вид» моего приложения у меня есть ContentControl, содержимое которого привязано к свойству CurrentPage.

Так что, когда я использую следующий код WPF не найти правильный DataTemplate

<UserControl ...> 
    <ContentControl Content="{Binding CurrentPage, Mode=OneWay}" 
        VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> 
     <ContentControl.Resources> 
      <DataTemplate DataType="{x:Type operation:OperationListPageVM}"> 
       <pages1:OperationListPageV/> 
      </DataTemplate> 
      <DataTemplate DataType="{x:Type operation:OperationDetailPageVM}"> 
       <pages1:OperationDetailPageV/> 
      </DataTemplate> 
      <DataTemplate DataType="{x:Type part:PartListPageVM}"> 
       <pages1:PartListPageV/> 
      </DataTemplate> 
      <DataTemplate DataType="{x:Type part:PartDetailPageVM}"> 
       <pages1:PartDetailPageV/> 
      </DataTemplate> 
      <DataTemplate DataType="{x:Type pages:SettingsPageVM}"> 
       <pages1:SettingsPageV/> 
      </DataTemplate> 
     </ContentControl.Resources> 
    </ContentControl> 
</UserControl> 

Но если я только положить один DataTemplate, как ContentControl.ContentTemplate тогда он будет применять его правильно

<UserControl ...> 
    <ContentControl Content="{Binding CurrentPage, Mode=OneWay}" 
        VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> 
     <ContentControl.ContentTemplate> 
      <DataTemplate DataType="{x:Type operation:OperationListPageVM}"> 
       <pages1:OperationListPageV/> 
      </DataTemplate> 
     </ContentControl.ContentTemplate> 
    </ContentControl> 
</UserControl> 

Если я затем положить эти DataTemplates обратно в качестве ресурсов, дать им ключ и создать DataTemplateSelector и добавить

ContentTemplateSelector="{StaticResource PageTemplateSelector}" 

К ControlTemplate с DataTemplateSelector как это:

using System.Windows; 
using System.Windows.Controls; 
using MaintenanceModuleV3.ViewModel; 
using MaintenanceModuleV3.ViewModel.Pages; 
using MaintenanceModuleV3.ViewModel.Pages.Operation; 
using MaintenanceModuleV3.ViewModel.Pages.Part; 

namespace MaintenanceModuleV3.View.TemplateSelector { 
    public class PageTemplateSelector : DataTemplateSelector { 
     public override DataTemplate SelectTemplate(object item, DependencyObject container) { 
      if (AppVM.Instance.CurrentPage != null) { 
       if (AppVM.Instance.CurrentPage is OperationListPageVM) { 
        return (container as FrameworkElement).FindResource("OperationListPageTemplate") as DataTemplate; 
       } else if (AppVM.Instance.CurrentPage is OperationDetailPageVM) { 
        return (container as FrameworkElement).FindResource("OperationDetailPageTemplate") as DataTemplate; 
       } else if (AppVM.Instance.CurrentPage is PartListPageVM) { 
        return (container as FrameworkElement).FindResource("PartListPageTemplate") as DataTemplate; 
       } else if (AppVM.Instance.CurrentPage is PartDetailPageVM) { 
        return (container as FrameworkElement).FindResource("PartDetailPageTemplate") as DataTemplate; 
       } else if (AppVM.Instance.CurrentPage is SettingsPageVM) { 
        return (container as FrameworkElement).FindResource("SettingsPageTemplate") as DataTemplate; 
       } 
      } 
      return null; 
     } 
    } 
} 

Тогда правая DataTemplate будет выбран.

Почему WPF не выбирает правильный DataTemplate, если я помещаю DataTemplates в ресурсы элемента в этом случае?

Спасибо

NB: Использование Framework 3.5

EDIT: Я заметил, что вторая проблема: DataContext Внутри DataTemplates равны нулю. Почему это? Почему они не будут использовать CurrentPage в качестве DataContext? Это тот случай, когда я непосредственно устанавливал ContentTemplate. WPF, похоже, не любит привязки к свойствам интерфейса.

EDIT 2: Если я устанавливаю DataContext OperListPageV явно в свой конструктор и использую TemplateSelector, все работает, но зачем мне это использовать?

EDIT 3: Полный код ViewModel, если это помогает:

Приложение ViewModel

public class AppVM : INotifyPropertyChanged { 

    #region constructor 
    private AppVM() { 
     AppM.LanguageChanged += (sender, args) => { 
      onPropertyChanged("CurrentLanguage"); 
     }; 

     AppM.NbDaysAvgChanged += (sender, args) => { 
      onPropertyChanged("NbDaysAvg"); 
     }; 

     AppM.NbDaysMenuNotificationChanged += (sender, args) => { 
      onPropertyChanged("NbDaysMenuNotification"); 
     }; 
    } 
    #endregion 

    #region business 

    #endregion 

    #region events 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void onPropertyChanged(string propertyName) { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    #endregion 

    #region properties 

    private static AppVM _instance; 
    public static AppVM Instance { 
     get { return _instance ?? (_instance = new AppVM()); } 
    } 


    #region notifypropertychanged 
    private OperationListPageVM _currentPage = OperationListPageVM.Instance; 
    public OperationListPageVM CurrentPage { 
     get { return _currentPage; } 
     set { 
      _currentPage = value; 
      onPropertyChanged("CurrentPage"); 
     } 
    } 

    public Language CurrentLanguage { 
     get { return AppM.CurrentLanguage; } 
    } 

    public int NbDaysMenuNotification { 
     get { return AppM.NbDaysMenuNotification; } 
    } 

    public int NbDaysAvg { 
     get { return AppM.NbDaysAvg; } 
    } 

    public Dictionary<String, String> AvailableTranslations { 
     get { return AppM.AvailableTranslations; } 
    } 
    #endregion 
    #region commands 
    #endregion 
    #endregion 
} 

страница Я был для отображения ViewModel

public sealed class OperationListPageVM : INotifyPropertyChanged, IPage { 

    #region constructor 
    private OperationListPageVM() { 
     //fill the available operations with data stored in the App Model coming from the DataBase 
     foreach (MaintenanceOperation operation in AppM.Operations) { 
      AvailableOperations.Add(new MaintenanceOperationVM(operation)); 
     } 
     foreach (MaintenanceOperationVM operation in AvailableOperations) { 
      DisplayedOperations.Add(operation); 
     } 
    } 
    #endregion 

    #region business 

    #endregion 

    #region events 
    public event PropertyChangedEventHandler PropertyChanged; 

    private void onPropertyChanged(string propertyName) { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    #endregion 

    #region properties 

    private static OperationListPageVM _instance; 

    public static OperationListPageVM Instance { 
     get { return _instance ?? (_instance = new OperationListPageVM()); } 
    } 

    #region notifypropertychanged 
    private ObservableCollection<MaintenanceOperationVM> _displayedOperations = new ObservableCollection<MaintenanceOperationVM>(); 
    public ObservableCollection<MaintenanceOperationVM> DisplayedOperations { 
     get { return _displayedOperations; } 
     set { 
      _displayedOperations = value; 
      onPropertyChanged("DisplayedOperations"); 
     } 
    } 

    private readonly List<MaintenanceOperationVM> _availableOperations = new List<MaintenanceOperationVM>(); 

    internal List<MaintenanceOperationVM> AvailableOperations { 
     get { return _availableOperations; } 
    } 

    #endregion 

    #region commands 

    #endregion 

    #endregion 
} 

В Просмотр слоя страницы, которую я должен был отобразить (OperationListPageV)

<UserControl x:Class="MaintenanceModuleV3.View.Pages.OperationListPageV" 
      ...> 
    <touch:ScrollFriction2> 
     <ListBox ItemsSource="{Binding DisplayedOperations}"> 
       <ListBox.ItemContainerStyle> 
        <Style TargetType="{x:Type ListBoxItem}"> 
         <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
        </Style> 
       </ListBox.ItemContainerStyle> 
      <ListBox.ItemTemplate> 
       <DataTemplate DataType="{x:Type viewModel:MaintenanceOperationVM}"> 
        <view:MaintenanceOperationV/> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </touch:ScrollFriction2> 
</UserControl> 

Если вам нужно больше кода, просто попросите его. Спасибо!

+0

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/65201/discussion-on-question-by-nkoniishvt-why-wont-wpf-choose-the-right-datatemplate). – Flexo

ответ

0

положите шаблоны в Ресурсы вашего ItemControl. Я не знаю, почему они сделали это таким образом, но они должны быть на один уровень выше вашего ContentControl.

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