想要一种使用 属性 编写 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
- 创建字典
在应用程序启动时填写此字典(看起来像您的磁贴列表)
public void PreCreateVMs()
{
dictionary[Key] = new ConcreteViewModelType();
// 继续在这里添加新的虚拟机
}
在 xaml 中,将所有按钮绑定到采用字符串参数的同一命令(或使用枚举即兴创作)。为每个按钮传递正确的字符串键。
比如:Accounts Button 单击应该启动 AccountVM,它在字典中用 "AccountVM" 键存储。
- 在命令处理程序中 - 使用字符串,查找字典找到正确的 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
定义为字典吗?
我们有一个 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- 创建字典
在应用程序启动时填写此字典(看起来像您的磁贴列表)
public void PreCreateVMs() { dictionary[Key] = new ConcreteViewModelType(); // 继续在这里添加新的虚拟机 }
在 xaml 中,将所有按钮绑定到采用字符串参数的同一命令(或使用枚举即兴创作)。为每个按钮传递正确的字符串键。 比如:Accounts Button 单击应该启动 AccountVM,它在字典中用 "AccountVM" 键存储。
- 在命令处理程序中 - 使用字符串,查找字典找到正确的 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
定义为字典吗?