【发布时间】:2020-01-29 22:56:13
【问题描述】:
我们有一个 WPF 应用程序,其登录页面列出了大约十几个按钮,所有按钮都指向该类型的新视图/视图模型。它变得笨拙。我们有一个视图模型,列出了所有这些,基本上如下所示:
private void ExecuteViewProgramCommand()
{
OpenViewMessage message = new OpenViewMessage();
CurrentViewModel = message.ViewModel = ViewModelLocator.ProgramVM;
Messenger.Default.Send<OpenViewMessage>(message);
}
我从不喜欢这样做的方式,因为它违反了 DRY 原则。上面第二行代码中唯一发生变化的地方是ViewModelLocator.ProgramVM。我的任务是重做登录页面,使其更有条理,我们将添加更多启动按钮。我认为使用依赖注入会更好。此外,我正在尝试解决重新设计显示的需要,以便它在列表中,而不是按字母顺序分散的按钮。
首先我想出了这个类:
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 的设置器中的分配将实例化 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 类以将 ModuleViewModel 属性声明为如下所示:public NamedViewModelBase ModuleViewModel { get; }。但我不知道在定义列表时如何实例化它。解决这个问题的正确方法是什么?
【问题讨论】:
-
如果您的 VM 具有最少的 ctors(没有 db 调用等,只有 init),那么您可以创建它们的 ObservableCollection 并分配一个按钮作为列表视图的模板,以便以这种方式使用和呈现它们。我知道 IoC 给人的印象是自动解析解决方案,但它实际上只是一组美化的全局变量。
-
你的问题有点不清楚。鉴于您当前的
Tile实现,您可以将其ModuleViewModel属性设置为任何视图模型。您的问题到底是什么? -
mm8,问题在于确保如果用户点击 Program 3 次,他们总是会获得 ProgramViewModel 的新实例。我实现
Tile类的方式,他们会得到相同的实例,这是我不能允许的。 -
如果我展示我们如何实例化一个新的虚拟机,比如 ProgramVM,这可能是最好的。以下代码来自我们的 ViewModelLocator: static public ProgramViewModel ProgramVM { get { if (ServiceLocator.IsLocationProviderSet) { SimpleIoc ioc = ServiceLocator.Current as SimpleIoc;返回 ioc.GetInstanceWithoutCaching
(Guid.NewGuid().ToString()); } 否则 { 返回空值; } } }
标签: c# wpf mvvm-light