想要一种使用 属性 编写 class 的方法,这将 return 一个 ViewModel 的新实例

Want a way to write a class with a property that will return a new instance of a ViewModel

我们有一个 WPF 应用程序,其登录页面列出了大约十几个按钮,所有按钮都将成为该类型的新 views/viewmodels。它变得笨重。我们有一个列出所有这些的视图模型,基本上看起来像这样:

    private void ExecuteViewProgramCommand()
    {
        OpenViewMessage message = new OpenViewMessage();
        CurrentViewModel = message.ViewModel = ViewModelLocator.ProgramVM;
        Messenger.Default.Send<OpenViewMessage>(message);
    }

我一直不喜欢这样做的方式,因为它违反了 DRY 原则。上面代码中唯一改变的是第二行,在此代码中改变的是 ViewModelLocator.ProgramVM。我的任务是重做登陆页面,使其更有条理,我们将添加更多启动按钮。我认为使用依赖注入会更好。此外,我正在尝试解决重新设计显示的需要,以便它在列表中,而不是散落在各处的按钮,并按字母顺序排列。

首先我想到了这个 class:

public class Tile
{
    public string ModuleName { get; set; }
    public NamedViewModelBase ModuleViewModel { get; set; }
}

(NamedViewModelBase 是所有视图模型通用的视图模型的名称。)然后我声明了一个单元测试来测试它,并在单元测试中声明了它:

List<Tile> tiles = new List<Tile>()
{
    new Tile()
    {
        ModuleName = "Program",
        ModuleViewModel = ViewModelLocator.ProgramVM
    },
    new Tile()
    {
        ModuleName = "Organization",
        ModuleViewModel = ViewModelLocator.OrganizationVM
    }
}

但这很快就证明这是错误的。 ViewModelLocator.ProgramVM 的 setter 中的分配将实例化 Program 的视图模型。我不想要那个,我宁愿调用实例化它,就像我们在 ViewModelLocator:

static public ProgramViewModel ProgramVM
{
    get
    {
        if (ServiceLocator.IsLocationProviderSet)
        {
            SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
            return ioc.GetInstanceWithoutCaching<ProgramViewModel>(Guid.NewGuid().ToString());
        }
        else
        {
            return null;
        }
    }
}

所以,我认为我必须更改 Tile class 以将 ModuleViewModel 属性 声明为如下内容:public NamedViewModelBase ModuleViewModel { get; }。但是我不知道在定义列表时如何实例化它。解决这个问题的正确方法是什么?

这将是伪装的 codish 建议,它与您已经在的同一条轨道上:

假设 BaseViewModel 是您所有个人 VM

的基础 class
  1. 创建字典
  2. 在应用程序启动时填写此字典(看起来像您的磁贴列表)

    public void PreCreateVMs() { dictionary[Key] = new ConcreteViewModelType(); // 继续在这里添加新的虚拟机 }

  3. 在 xaml 中,将所有按钮绑定到采用字符串参数的同一命令(或使用枚举即兴创作)。为每个按钮传递正确的字符串键。 比如:Accounts Button 单击应该启动 AccountVM,它在字典中用 "AccountVM" 键存储。

  4. 在命令处理程序中 - 使用字符串,查找字典找到正确的 ViewModel 并将此对象分配给 CurrentViewModel

从维护的角度来看 - 添加新 ViewModel 所需要做的就是使用新按钮更新 xaml,分配正确的命令参数字符串。使用此字符串键并在 PreCreateVMs 方法中添加正确的 VM。

我重新设计了 Tile class。我相信我需要的是第二个参数是命令。我在问这是否可以做得更好。这是 Tile 的新定义以及我如何尝试实现它的示例:

public class Tile
{
    public string ModuleName { get; set; }
    //public NamedViewModelBase ModuleViewModel { get; set; }
    public Action ThisCommand { get; set; }
}

下面是我尝试将其实现为列表的方式:

List<Tile> tiles = new List<Tile>()
{
    new Tile()
    {
        ModuleName = "Program",
        ThisCommand = () => 
        {
            if (ServiceLocator.IsLocationProviderSet)
            {
                SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
                ioc.GetInstanceWithoutCaching<ProgramViewModel>(Guid.NewGuid().ToString());
            }
        }
    },
    new Tile()
    {
        ModuleName = "Organization",
        ThisCommand = () =>
        {
            if (ServiceLocator.IsLocationProviderSet)
            {
                SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;
                ioc.GetInstanceWithoutCaching<OrganizationViewModel>(Guid.NewGuid().ToString());
            }
        }
    }
};

我走在正确的轨道上吗?我应该将 tiles 定义为字典吗?