我通过构建一个解决我工作中遇到的简单问题的例子来教自己MVVM光。我们有两个ID记录,一个记录为long
,一个记录为int
。对于大型ID,int
字段包含在内。此计划会显示给定long
的可能int
个ID。
我正在尝试使用SimpleIoc
DataServices,所以这个例子比它需要的要复杂得多。
DataService是一个简单的类(CallIDConverter
),它保存ID并计算其他值,如果给出int
,则计算其他可能的long
值。
当用户键入新值时,正在更新类,因此正在调用RaisePropertyChanged()
,但视图未更新。这是由于我使用DataService
的方式吗?或者我只是在某个地方错过了RaisePropertyChanged()
。
ViewModelLocator.cs:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, CallIdDataService>();
}
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main
{
get { ServiceLocator.Current.GetInstance<MainViewModel>(); }
}
}
CallIdDataService.cs:
public class CallIdDataService : IDataService
{
public void GetData(Action<CallIdConverter, Exception> callback)
{
var item = new CallIdConverter();
callback(item, null);
}
}
CallIDConverter.cs
public class CallIdConverter : ObservableObject
{
private static long _totalNumberOfInts = Convert.ToInt64(Int32.MaxValue) - Convert.ToInt64(Int32.MinValue) + 1;
private int _shorewareCallID;
private long _ccirPrimaryID;
private List<long> _ccirPossiblePrimaryIDs;
public int ShorewareCallID { get { return _shorewareCallID; } }
public long CCIRPrimaryID { get { return _ccirPrimaryID; } }
public ReadOnlyCollection<long> CCIRPossiblePrimaryIDs { get { return _ccirPossiblePrimaryIDs.AsReadOnly(); } }
public CallIdConverter()
{
this._shorewareCallID = 0;
this._ccirPrimaryID = 0L;
this._ccirPossiblePrimaryIDs = new List<long>();
}
public void SetShorewareCallID(int callID)
{
this._shorewareCallID = callID;
this._ccirPrimaryID = callID > 0L ? (long)callID : (long)callID + _totalNumberOfInts;
this._ccirPossiblePrimaryIDs.Clear();
for (int i = 0; i < 5; i++)
{
_ccirPossiblePrimaryIDs.Add((long)callID + (i * _totalNumberOfInts));
}
RaisePropertyChanged(() => ShorewareCallID);
RaisePropertyChanged(() => CCIRPrimaryID);
RaisePropertyChanged(() => CCIRPossiblePrimaryIDs);
}
public void SetCCIRPrimaryID(long primaryID)
{
this._shorewareCallID = (int)primaryID;
this._ccirPrimaryID = primaryID;
this._ccirPossiblePrimaryIDs.Clear();
RaisePropertyChanged(() => ShorewareCallID);
RaisePropertyChanged(() => CCIRPrimaryID);
RaisePropertyChanged(() => CCIRPossiblePrimaryIDs);
}
}
MainViewModel.cs:
public class MainViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private CallIdConverter Data { get; set; }
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
if (error != null)
{
// Report error here
return;
}
this.Data = item;
});
}
public int ShorewareCallID
{
get { return Data.ShorewareCallID; }
set
{
if (Data.ShorewareCallID == value) { return; }
Data.SetShorewareCallID(value);
RaisePropertyChanged(() => Data);
}
}
public long CCIRPrimaryID
{
get { return Data.CCIRPrimaryID; }
set
{
if (Data.CCIRPrimaryID == value) { return; }
Data.SetCCIRPrimaryID(value);
RaisePropertyChanged(() => Data);
}
}
public ObservableCollection<long> CCIRPossiblePrimaryIDs
{
get { return new ObservableCollection<long>(Data.CCIRPossiblePrimaryIDs); }
}
}
在摆弄之后,我发现如果我替换
它会起作用RaisePropertyChanged(() => Data);
与
RaisePropertyChanged(() => ShorewareCallID);
RaisePropertyChanged(() => CCIRPrimaryID);
RaisePropertyChanged(() => CCIRPossiblePrimaryIDs);
这意味着CallIDConverter
不需要继承ObservableObject
。这个问题是ViewModel需要知道在模型类上调用方法时受影响的所有内容。在我看来这不是一个好主意。