我正在创建一个用于管理在线赛车联赛的小型应用程序。 为此,我将拥有一个数据库,该数据库可从Web访问数据并通过接口公开数据对象。该数据库尚不存在,但我创建了一个使用本地XML文件作为数据源的模型。
联赛界面的小示例:
void (*scanCompleteCB)(BLEScanResults)
现在,使用MVVM模式将其放入我的WPF中,我为数据库暴露的每个对象创建了一个模型,并在那里实现了INPC。
*注意:public interfac ISchedule
{
string Name { get; set; }
List<IRaceSession> Races { get; }
// and some more properties …
IRaceSession AddRace();
void RemoveRace(IRaceSession race);
// and some more Methods …
}
public interface IRaceSession
{
uint RaceId { get; }
DateTime Date { get; set; }
TimeSpan Duration { get; set; }
// and some more properties …
}
和ContainerModel<>
是我创建的类,用于处理数据库中的更新,同时仍保持INPC不变。
ObservableModelCollection<>
然后我有一个viewModel和一个直接绑定到Model属性的视图。
public class ContainerModel<T>
{
T Source { get; set; }
public ContainerModel(T source)
{
Source = source;
}
void UpdateSource(T source)
{
// handle updates …
}
}
public class ScheduleModel : ISchedule, ContainerModel<ISchedule>
{
public string Name { get => Source.Name ; set { Source.Name = value; NotifyPropertyChanged(); } }
public ObservableModelCollection<RaceSessionModel, IRaceSession> Races { get; }
List<IRaceSession> ISchedule.Races => Source.Races
public ScheduleModel(ISchedule source) : base(source)
{
Races = new ObservableModelCollection<RaceSessionModel, IRaceSession>(Source.Races);
}
IRaceSession AddRace()
{
Races.Add(// new Race Object);
}
void RemoveRace(IRaceSession race)
{
Races.Remove(// select race object to remove);
}
}
public class RaceSessionModel : IRaceSession, ContainerModel<IRaceSession>
{
public uint RaceId => Source.RaceId;
puglic DateTime Date { get => Source.Date; set { Source.Date = value; NotifyPropertyChanged(); } }
TimeSpan Duration { get => Source.Duration; set { Source.Duration = value; NotifyPropertyChanged(); } }
//--> here come some more logic im not sure About:
TimeSpan DurationHours
{
get => Duration.Hours;
set
{
// set only Hours componennt of Duration
Duration = Duration
.Subtract(Duration.Hours)
.Add(value);
NotifyPropertyChanged();
}
TimeSpan DurationMinutes
{
get => Duration.Minutes;
set
{
// set only Minutes componennt of Duration
Duration = Duration
.Subtract(Duration.Minutes)
.Add(value);
NotifyPropertyChanged();
}
}
现在使用这种设计,我有一些担忧。我仍在摸索整个设计模式,这是我第一次从头开始构建它。
我的模型实际上并不包含数据,而只是公开数据库中的属性 我认为这实际上是viewModel应该做的事情对吗?
如您所见,我的模型还对属性Input进行了某种计算。该“业务逻辑”是否也应该放在模型之外?还是将其更好地放入ViewModel中?
毕竟,我完全怀疑我所呈现的是“模型”。称它们为ViewModels,然后将数据库中的Object用作模型,是否正确?
*编辑:
当我开始阅读时,我读到每个public class SchedulerViewModel : ViewModelBase //<-- just a Basic implementation of INPC
{
private ScheduleModel _schedule;
public ScheduleModel Schedule { get => _schedule; set { _schedule = value; NotifyPropertyChanged(); } }
public SchedulerViewModel(ScheduleModel schedule)
{
Schedule = schedule;
}
// Commands and other properties communicating with the view
// …
}
应该只提供一个View
,这就是为什么我创建这样的类的原因。但是我不确定这是否正确。
答案 0 :(得分:1)
为了将数据从模型传输到ViewModel,我将创建简单的对象(Dto-DataTransferObject),而没有(或非常少的)逻辑。 一个很好的经验法则是,您希望ViewModel中的未保存数据属于模型中的已保存数据或即将要保存的数据。
//--> here come some more logic im not sure About:
TimeSpan DurationHours
{
get => Duration.Hours;
set
{
// set only Hours componennt of Duration
Duration = Duration
.Subtract(Duration.Hours)
.Add(value);
NotifyPropertyChanged();
}
TimeSpan DurationMinutes
{
get => Duration.Minutes;
set
{
// set only Minutes componennt of Duration
Duration = Duration
.Subtract(Duration.Minutes)
.Add(value);
NotifyPropertyChanged();
}
我会将它们放入ViewModel中。在模型中,您需要整个Timespan对象,只有ViewModel应该知道只能在View中单独设置它们的限制。
当我开始阅读此书时,我会阅读您应该提供的每个视图 只有一个ViewModel,这就是为什么我这样创建类的原因。但 我不确定这是否正确。
是的,当您必须维护代码并进行仅适用于单个View的更改时,此操作以后可以省去很多麻烦。
答案 1 :(得分:1)
这可能在很大程度上取决于您要对应用程序执行的操作,但是通常我会这样处理:
从本质上讲,我一直认为模型几乎只是代表数据库中的一行。在应用程序外部独立存在的基本数据实体。那么ViewModel就是仅与应用程序相关的任何东西。
在计划模型中没有集合RaceSession模型的原因是,如果您要对RaceSession进行任何基于应用程序的操作,那便属于ViewModel,所以您d然后正在查看带有RaceSessionViewModels集合的Schedule Model。因此,我将把Models严格保持为单个数据实体,而没有内置任何类型的实体关系(联接)-这些类型的关系将内置到ViewModel层中。即使您不需要RaceSession的ViewModel,在Schedule ViewModel中仍然有RaceSession模型的集合。
作为上述示例,我相信AddRace
方法确实属于Schedule ViewModel,而不是Schedule Model。
关于TimeSpan
的计算,我可能将Hours and Minutes作为get
的唯一属性(在RaceSession ViewModel上),并在RaceSessionViewModel上使用其他方法来更改{{1 }}属性。具体的实现取决于更新时是否在数据库中实际更改它们。
一些伪代码示例
Duration
答案 2 :(得分:0)