背景与问题
我有一个WPF应用程序,该应用程序基本上由一组不同的Skill对象组成,其中每个技能都从抽象基类(SkillBase)继承而来.每个技能应具有自己的View和ViewModel以支持编辑特定技能的值.当用户在列表中选择一项技能并按下“编辑”时,应使用注入的技能实例化相应的Edit-ViewModel.
当我只有一个Skill-data对象时,如何选择应该实例化的Edit-ViewModel?可以通过插件系统添加技能,因此我事先不知道技能的类型.
我今天的解决方案(有效)是用一个属性(EditViewModelForAttribute)装饰每个Edit-ViewModel,该属性告诉它应映射到什么数据类型.这是走的路还是有更好的方法呢?我是否在正确的轨道上?
我能想到的其他解决方案是跳过属性并使用Edit-ViewModels的某种命名约定,另一种解决方案是在启动时通过注入的服务(EditService.RegisterEditViewModel)将技能类型注册为Edit-ViewModel类型. (typeof(WalkSkill),typeof(EditWalkSkillViewModel));)
这是我的代码:
“数据层”
public abstract class SkillBase
{
// Common properties for all skills
}
public class WalkSkill : SkillBase
{
// Some properties
}
public class RunSkill : SkillBase
{
// Some properties
}
“ ViewModel层”
public abstract class EditSkillViewModel<T> : ViewModelBase where T : Skill
{
public abstract T Skill { get; protected set; }
}
[EditViewModelFor(typeof(WalkSkill))] // Attribute telling that this viewmodel should be instantiated when we want to edit a WalkSkill object
public class EditWalkSkillViewModel : EditSkillViewModel<WalkSkill>
{
public override WalkSkill Skill { get; protected set; }
public EditWalkSkillViewModel(WalkSkill skill)
{
Skill = skill;
}
}
[EditViewModelFor(typeof(RunSkill))] // Attribute telling that this viewmodel should be instantiated when we want to edit a RunSkill object
public class EditRunSkillViewModel : EditSkillViewModel<RunSkill>
{
public override RunSkill Skill { get; protected set; }
public EditRunSkillViewModel(RunSkill skill)
{
Skill = skill;
}
}
要为特定技能找到正确的ViewModel,我有一个扩展方法来搜索具有EditViewModelForAttribute和特定技能类型的应用程序域中的类型:
public static ViewModelBase GetEditSkillViewModel(this Skill skill)
{
var viewModelType = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where
type.IsDefined(typeof(EditViewModelForAttribute)) &&
type.GetCustomAttribute<EditViewModelForAttribute>().SkillType == skill.GetType()
select type).SingleOrDefault();
return viewModelType == null ? null : (ViewModelBase)Activator.CreateInstance(viewModelType, skill);
}
如下所示:
var editViewModel = selectedSkill.GetEditSkillViewModel();
解决方法:
对于我来说,当前使用的解决方案看起来不错,只要每个技能只有一个ViewModel.
但是,有一个建议是使用FirstOrDefault而不是SingleOrDefault并将结果缓存在某个位置.搜索所有类型可能很耗时.