ror*_*.ap 8 c# abstraction dependency-injection mvvm separation-of-concerns
我有一个应用程序从输入文件加载客户端/事项编号列表,并在UI中显示它们.这些数字是简单的零填充数字字符串,如"02240/00106".这是ClientMatter
班级:
public class ClientMatter
{
public string ClientNumber { get; set; }
public string MatterNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我正在使用MVVM,它使用依赖注入和UI中包含的组合根.有一个IMatterListLoader
服务接口,其中实现表示从不同文件类型加载列表的机制.为简单起见,假设只有一个实现与应用程序一起使用,即应用程序目前不支持多种文件类型.
public interface IMatterListLoader
{
IReadOnlyCollection<string> MatterListFileExtensions { get; }
IReadOnlyCollection<ClientMatter> Load(FileInfo fromFile);
}
Run Code Online (Sandbox Code Playgroud)
让我们说在我的初始版本中,我选择了一个MS Excel实现来加载事项列表,如下所示:
我想允许用户在运行时配置列表开始的行号和列号,因此视图可能如下所示:
这是MS Excel的实现IMatterListLoader
:
public sealed class ExcelMatterListLoader : IMatterListLoader
{
public uint StartRowNum { get; set; }
public uint StartColNum { get; set; }
public IReadOnlyCollection<string> MatterListFileExtensions { get; set; }
public IReadOnlyCollection<ClientMatter> Load(FileInfo fromFile)
{
// load using StartRowNum and StartColNum
}
}
Run Code Online (Sandbox Code Playgroud)
行号和列号是特定于MS Excel实现的实现细节,并且视图模型不知道它.然而,MVVM决定了我控制视图模型视图属性,所以如果我是这样做,这将是这样的:
public sealed class MainViewModel
{
public string InputFilePath { get; set; }
// These two properties really don't belong
// here because they're implementation details
// specific to an MS Excel implementation of IMatterListLoader.
public uint StartRowNum { get; set; }
public uint StartColNum { get; set; }
public ICommandExecutor LoadClientMatterListCommand { get; }
public MainViewModel(IMatterListLoader matterListLoader)
{
// blah blah
}
}
Run Code Online (Sandbox Code Playgroud)
仅作比较,这是一个基于ASCII文本文件的实现,我可能会考虑下一个版本的应用程序:
public sealed class TextFileMatterListLoader : IMatterListLoader
{
public bool HasHeaderLine { get; set; }
public IReadOnlyCollection<string> MatterListFileExtensions { get; set; }
public IReadOnlyCollection<ClientMatter> Load(FileInfo fromFile)
{
// load tab-delimited client/matters from each line
// optionally skipping the header line.
}
}
Run Code Online (Sandbox Code Playgroud)
现在我没有MS Excel实现所需的行号和列号,但是我有一个布尔标志,指示客户端/事项编号是从第一行开始(即没有标题行)还是从第二行开始(即带标题行).
我相信视图模型应该不知道实现之间的变化IMatterListLoader
.如何让视图模型完成控制演示文稿问题的工作,但仍然保留某些未知的实现细节?
这是依赖关系图:
对于要加载的每种类型的文件,您都需要一个单独的视图模型。
每个视图模型都为其特定的加载器进行设置。
然后可以将这些视图模型作为依赖项传递给主视图模型,主视图模型在需要时调用每个视图模型;
public interface ILoaderViewModel
{
IReadOnlyCollection<ClientMatter> Load();
}
public class ExcelMatterListLoaderViewModel : ILoaderViewModel
{
private readonly ExcelMatterListLoader loader;
public string InputFilePath { get; set; }
public uint StartRowNum { get; set; }
public uint StartColNum { get; set; }
public ExcelMatterListLoaderViewModel(ExcelMatterListLoader loader)
{
this.loader = loader;
}
IReadOnlyCollection<ClientMatter> Load()
{
// Stuff
loader.Load(fromFile);
}
}
public sealed class MainViewModel
{
private ExcelMatterListLoaderViewModel matterListLoaderViewModel;
public ObservableCollection<ClientMatter> ClientMatters
= new ObservableCollection<ClientMatter>();
public MainViewModel(ExcelMatterListLoaderViewModel matterListLoaderViewModel)
{
this.matterListLoaderViewModel = matterListLoaderViewModel;
}
public void LoadCommand()
{
var clientMatters = matterListLoaderViewModel.Load();
foreach (var matter in clientMatters)
{
ClientMatters.Add(matter)
}
}
}
Run Code Online (Sandbox Code Playgroud)
当您向应用程序添加更多类型时,您将创建新的视图模型并将它们添加为依赖项。