我的 ViewModel 中有 4 个实现 IPage 接口(我创建的接口)的类。在我的应用程序的 ViewModel 中,我有一个 IPage 类型的 CurrentPage 属性。
在我的应用程序的 View 层中,我有一个 ContentControl,它的 Content 绑定到 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}"
到带有 DataTemplateSelector 的 ControlTemplate,如下所示:
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。
如果我在这种情况下将 DataTemplates 放在元素资源中,为什么 WPF 不会选择正确的 DataTemplate?
谢谢
注意:使用框架 3.5
编辑:我注意到第二个问题:DataTemplates 中的 DataContext 为空。这是为什么?他们为什么不将 CurrentPage 作为 DataContext?当我直接设置 ContentTemplate 也是这种情况。WPF 似乎不喜欢绑定到接口类型的属性。
编辑 2:如果我在其构造函数中明确设置 OperationListPageV 的 DataContext 并使用 TemplateSelector 一切正常,但为什么我必须使用这些?
编辑 3:完整的 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>
如果您需要更多代码,请索取。谢谢!