这是我的
InheritanceDataTemplateSelector
,它只与接口一起使用。
namespace MyWpf;
using Sys = System;
using Wpf = System.Windows;
using WpfControls = System.Windows.Controls;
public class InterfaceDataTemplateSelector : WpfControls.DataTemplateSelector
{
delegate object? ResourceFinder( object key );
public override Wpf.DataTemplate? SelectTemplate( object item, Wpf.DependencyObject container )
{
ResourceFinder resourceFinder = getResourceFinder( container );
return tryGetDataTemplateRecursively( item.GetType(), resourceFinder );
}
static ResourceFinder getResourceFinder( Wpf.DependencyObject container )
=> (container is Wpf.FrameworkElement containerAsFrameworkElement)
? containerAsFrameworkElement.TryFindResource
: Wpf.Application.Current.TryFindResource;
static Wpf.DataTemplate? tryGetDataTemplateRecursively( Sys.Type type, ResourceFinder resourceFinder )
{
return tryGetDataTemplateFromType( type, resourceFinder )
?? tryGetDataTemplateFromInterfacesRecursively( type, resourceFinder )
?? tryGetDataTemplateFromSuperTypeRecursively( type, resourceFinder );
}
static Wpf.DataTemplate? tryGetDataTemplateFromType( Sys.Type type, ResourceFinder tryFindResource )
{
Wpf.DataTemplateKey resourceKey = new Wpf.DataTemplateKey( type );
object? resource = tryFindResource( resourceKey );
if( resource is Wpf.DataTemplate dataTemplate )
{
if( !dataTemplate.IsSealed )
dataTemplate.DataType = type;
return dataTemplate;
}
return null;
}
static Wpf.DataTemplate? tryGetDataTemplateFromInterfacesRecursively( Sys.Type type, ResourceFinder resourceFinder )
{
foreach( var interfaceType in type.GetInterfaces() )
{
Wpf.DataTemplate? dataTemplate = tryGetDataTemplateRecursively( interfaceType, resourceFinder );
if( dataTemplate != null )
return dataTemplate;
}
return null;
}
static Wpf.DataTemplate? tryGetDataTemplateFromSuperTypeRecursively( Sys.Type type, ResourceFinder resourceFinder )
{
return type.BaseType == null ? null : tryGetDataTemplateRecursively( type.BaseType, resourceFinder );
}
}
如何使用:
在您的“资源”部分中,像往常一样定义每个“DataTemplate”,但现在每个“DataType”都是一个接口而不是具体类型:
<DataTemplate DataType="{x:Type viewModels:MyViewModelInterface}">
<local:MyView />
</DataTemplate>
然后,为
InheritanceDataTemplateSelector
添加一个额外的资源:
<myWpf:InterfaceDataTemplateSelector x:Key="InterfaceDataTemplateSelector" />
然后,在需要使用的正确位置,指定应该使用这个选择器。例如,在一个中:
<ItemsControl ItemsSource="{Binding SomeViewModelCollection}"
ItemTemplateSelector="{StaticResource InterfaceDataTemplateSelector}">
注意:ViewModel接口
不必扩展INotifyPropertyChanged。ViewModel的具体实现
可以实现它,
如果需要的话。
另外请注意:与其他答案所建议的相反,在绑定到接口ViewModel的成员时,没有必要使用任何特殊的符号。(至少在最近版本的WPF中是如此。)
ContentControl
,根据传递给IValueConverter
的DataContext
和接口设置它的ContentTemplate
,这样怎么样?然后您可以测试值是否是与参数传递的类型相同,如果为 True,则使用适当的 DataTemplate。 - Rachel