MVVM ViewModel 到模型通信和参数
MVVM ViewModel to Model communication and parameters
背景
我想我已经找到了这个问题的答案,但我正在努力尽可能地坚持 MVVM,并在很长一段时间内学到很多东西。
我目前已经设置好视图、视图模型和模型。我的模型正在使用 entity framework.
查询数据库
我的视图有一堆控件允许用户设置查询的参数(基本上构建一个大的 where 子句)。ViewModel 存储通过控件设置的这些选项。
所以我的视图-视图模型交互看起来很准确,我认为这是可以接受的。
问题
我的模型公开了一个函数,该函数 returns 将查询结果作为某种 IEnumerable。我现在遇到的问题是 "search criteria" 我让用户设置的数量。我现在有 9 模型函数的参数。不知道能不能接受至少,它是丑陋的。很丑陋。但是这样一来,我的 viewModel 只需要保存模型的一个实例,然后只需要知道那个函数及其签名。
问题
我应该在模型中设置属性,然后在视图模型中设置这些属性吗?这样单个函数会更清晰,但视图模型必须更多 "aware" 模型具有的属性。我知道创建一些 public 属性没什么大不了的,但我想知道哪个更适合 MVVM。我们当前的代码库没有关注点分离。所以我只能靠自己了。
有问题的代码
当前模型函数:
public IEnumerable<> GetResults(string id, string inputName, DateTime? fromDate,
DateTime? toDate, bool option1, int selectCount, bool exactMatch = true, bool showFailed = false)
{
//QUERY HERE, returns results
}
相关 ViewModel 调用:
var queryResults = MyModel.GetResults(id, inputname, FromDate, ToDate, Option1, selectCount, ExactMatch, ShowFailed);
Results = queryResults.ToList();
建议模型:
public string Id {get;set}
public string InputName {get;set}
public DateTime? FromDate {get;set}
public DateTime? ToDate {get;set}
public bool Option1 {get;set}
public int SelectCount {get;set}
public bool ExactMatch {get;set}
public bool ShowFailed {get;set}
public IEnumerable<> GetResults()
{
//Query here, return results
}
相关提议的 ViewModel 调用:
MyModel.Id = this.Id;
MyModel.InputName = this.InputName;
MyModel.FromDate = this.FromDate;
//...etc (I put the this. to clarify the view model also has those properties).
var results= MyModel.GetResults();
我会说,"It depends",这些参数之间的联系有多紧密。
能不能分成几组,功能多一点就好了。
例如按时间范围、严重程度、文本搜索等过滤。
当它们明显属于一起时,创建一个 class 或结构来对它们进行分组并传递单个参数。
想想其他人 'consumers' can/will 将来如何使用你的模型,并据此做出决定/
根据我的理解,您的用例要求实施 Command Query Separation. About CQS details you can see my answer 。现在我们有了这个作为我们想法基础的据点,我们将检查下一个重构步骤。
参数泛洪的重构
看到你的方法签名,我们可以清楚地看到你在这里有很多个参数:
public IEnumerable<T> GetResults(string id, string inputName, DateTime? fromDate,
DateTime? toDate, bool option1, int selectCount,
bool exactMatch = true, bool showFailed = false)
现在,如果我们引入 parameter object 而不是当前的九个参数,您的代码将如下所示:
public IEnumerable<T> GetResults(FilterObject filterObject)
看起来好多了吧?现在示例参数对象只是一个 POCO,看起来像:
public class FilterObject
{
public string id { get; set; }
public string inputName { get; set; }
...
}
分离获得结果的关注
分离关注点并摆脱紧耦合的模型和视图模型。可以找到关于查询的非常好的简短介绍 here。我们创建一个示例查询处理程序:
public class GetResultsQueryHandler
: IQueryHandler<FilterObject, YourModel>
{
public GetResultsQueryHandler([pass your needed dependencies here])
{
//set them to local variables
}
public YourModel Handle(FilterObject filterObject)
{
// Logic to call GetResults(filterObject) and return the filled model
}
}
现在你已经很好地分离了前一个 GetResults()
调用并且你的模型具有属性 "filled".
将模型映射到视图模型
我们最后需要做的是如何将模型映射到视图模型实例。有很多对象映射器,一个流行的是 AutoMapper。在像你这样的情况下,它会让你的生活更轻松,实际上你需要做的就是设置你的地图并调用 Mapper.Map()
。
在问题中显示的示例中,模型和视图模型 属性 名称相同,映射定义应该很简单:
public static void Configure()
{
Mapper.CreateMap<YourModel, YourViewModel>();
}
然后得到映射视图模型的结果,映射操作可以这样完成:
var viewModel = Mapper.Map<YourModel, YourViewModel>(model);
其中model
参数为填充模型。
关于我的 AutoMapper 示例中显示的静态用例方法的引用:
The 4.2.0 release of AutoMapper marked the entire static configuration and mapping API as obsolete
这意味着使用 AutoMapper >= v4.2 创建配置已更改为:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<YourModel, YourViewModel>();
});
var mapper = config.CreateMapper();
背景
我想我已经找到了这个问题的答案,但我正在努力尽可能地坚持 MVVM,并在很长一段时间内学到很多东西。
我目前已经设置好视图、视图模型和模型。我的模型正在使用 entity framework.
查询数据库我的视图有一堆控件允许用户设置查询的参数(基本上构建一个大的 where 子句)。ViewModel 存储通过控件设置的这些选项。
所以我的视图-视图模型交互看起来很准确,我认为这是可以接受的。
问题
我的模型公开了一个函数,该函数 returns 将查询结果作为某种 IEnumerable。我现在遇到的问题是 "search criteria" 我让用户设置的数量。我现在有 9 模型函数的参数。不知道能不能接受至少,它是丑陋的。很丑陋。但是这样一来,我的 viewModel 只需要保存模型的一个实例,然后只需要知道那个函数及其签名。
问题
我应该在模型中设置属性,然后在视图模型中设置这些属性吗?这样单个函数会更清晰,但视图模型必须更多 "aware" 模型具有的属性。我知道创建一些 public 属性没什么大不了的,但我想知道哪个更适合 MVVM。我们当前的代码库没有关注点分离。所以我只能靠自己了。
有问题的代码
当前模型函数:
public IEnumerable<> GetResults(string id, string inputName, DateTime? fromDate,
DateTime? toDate, bool option1, int selectCount, bool exactMatch = true, bool showFailed = false)
{
//QUERY HERE, returns results
}
相关 ViewModel 调用:
var queryResults = MyModel.GetResults(id, inputname, FromDate, ToDate, Option1, selectCount, ExactMatch, ShowFailed);
Results = queryResults.ToList();
建议模型:
public string Id {get;set}
public string InputName {get;set}
public DateTime? FromDate {get;set}
public DateTime? ToDate {get;set}
public bool Option1 {get;set}
public int SelectCount {get;set}
public bool ExactMatch {get;set}
public bool ShowFailed {get;set}
public IEnumerable<> GetResults()
{
//Query here, return results
}
相关提议的 ViewModel 调用:
MyModel.Id = this.Id;
MyModel.InputName = this.InputName;
MyModel.FromDate = this.FromDate;
//...etc (I put the this. to clarify the view model also has those properties).
var results= MyModel.GetResults();
我会说,"It depends",这些参数之间的联系有多紧密。
能不能分成几组,功能多一点就好了。 例如按时间范围、严重程度、文本搜索等过滤。
当它们明显属于一起时,创建一个 class 或结构来对它们进行分组并传递单个参数。
想想其他人 'consumers' can/will 将来如何使用你的模型,并据此做出决定/
根据我的理解,您的用例要求实施 Command Query Separation. About CQS details you can see my answer
参数泛洪的重构
看到你的方法签名,我们可以清楚地看到你在这里有很多个参数:
public IEnumerable<T> GetResults(string id, string inputName, DateTime? fromDate,
DateTime? toDate, bool option1, int selectCount,
bool exactMatch = true, bool showFailed = false)
现在,如果我们引入 parameter object 而不是当前的九个参数,您的代码将如下所示:
public IEnumerable<T> GetResults(FilterObject filterObject)
看起来好多了吧?现在示例参数对象只是一个 POCO,看起来像:
public class FilterObject
{
public string id { get; set; }
public string inputName { get; set; }
...
}
分离获得结果的关注
分离关注点并摆脱紧耦合的模型和视图模型。可以找到关于查询的非常好的简短介绍 here。我们创建一个示例查询处理程序:
public class GetResultsQueryHandler
: IQueryHandler<FilterObject, YourModel>
{
public GetResultsQueryHandler([pass your needed dependencies here])
{
//set them to local variables
}
public YourModel Handle(FilterObject filterObject)
{
// Logic to call GetResults(filterObject) and return the filled model
}
}
现在你已经很好地分离了前一个 GetResults()
调用并且你的模型具有属性 "filled".
将模型映射到视图模型
我们最后需要做的是如何将模型映射到视图模型实例。有很多对象映射器,一个流行的是 AutoMapper。在像你这样的情况下,它会让你的生活更轻松,实际上你需要做的就是设置你的地图并调用 Mapper.Map()
。
在问题中显示的示例中,模型和视图模型 属性 名称相同,映射定义应该很简单:
public static void Configure()
{
Mapper.CreateMap<YourModel, YourViewModel>();
}
然后得到映射视图模型的结果,映射操作可以这样完成:
var viewModel = Mapper.Map<YourModel, YourViewModel>(model);
其中model
参数为填充模型。
关于我的 AutoMapper 示例中显示的静态用例方法的引用:
The 4.2.0 release of AutoMapper marked the entire static configuration and mapping API as obsolete
这意味着使用 AutoMapper >= v4.2 创建配置已更改为:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<YourModel, YourViewModel>();
});
var mapper = config.CreateMapper();