【发布时间】:2013-03-15 08:33:03
【问题描述】:
当在MvxBindableTableViewCell 中使用时,我有点难以将更改从 ViewModel 反映到 View。我在 iOS 上使用 MvvmCross 的 vNext 分支。
一切都已正确设置,并且在首次加载/显示列表时可以看到初始值。该列表是一个ObservableCollection<T>,ViewModels 继承自MvxViewModel(因此实现了 INotifyPropertyChanged)。
主视图模型如下所示:
public abstract class BaseViewModel : MvxViewModel, IMvxServiceConsumer
{
//... just regular implementation
}
public class UploadListViewModel: BaseViewModel
{
private readonly IUploadItemTasks uploadItemTasks;
private readonly IPhotoPickerService photoPickerService;
public IObservableCollection<UploadItemViewModel> Uploads { get { return this.LoadUploadItems(); } }
public UploadListViewModel()
{
this.uploadItemTasks = this.GetService<IUploadItemTasks>();
this.photoPickerService = this.GetService<IPhotoPickerService>();
}
private IObservableCollection<UploadItemViewModel> LoadUploadItems()
{
using (var unitOfWork = UnitOfWork.Start ())
{
return new SimpleObservableCollection<UploadItemViewModel>(uploadItemTasks.GetAll());
}
}
public void StartUpload ()
{
if (this.Uploads == null || this.Uploads.Count == 0) {
ReportError("Error", "No images to upload");
return;
}
this.Uploads.ForEach (uploadItem => PostCallback (uploadItem));
}
private void PostCallback (UploadItemViewModel uploadAsset)
{
IProgressReporter progressReporter = uploadAsset;
this.photoPickerService.GetAssetFullImage(uploadAsset.ImageUrl,
(image) => {
UIImage fullImage = image;
NSData jpeg = fullImage.AsJPEG();
byte[] jpegBytes = new byte[jpeg.Length];
System.Runtime.InteropServices.Marshal.Copy(jpeg.Bytes, jpegBytes, 0, Convert.ToInt32(jpeg.Length));
MemoryStream stream = new MemoryStream(jpegBytes);
Uri destinationUrl = new Uri(uploadAsset.DestinationUrl + "&name=" + uploadAsset.Name + "&contentType=image%2FJPEG");
//TO DO: Move this to plugin
var uploader = new Uploader().UploadPicture (destinationUrl, stream, UploadComplete, progressReporter);
uploader.Host = uploadAsset.Host;
ThreadPool.QueueUserWorkItem (delegate {
uploader.Upload ();
jpeg = null;
});
});
}
private void UploadComplete (string name)
{
if (name == null){
ReportError("Error","There was an error uploading the media.");
} else
{
//ReportError("Succes", name);
}
}
项目 ViewModel 看起来像:
public interface IProgressReporter
{
float Progress { get; set;}
}
public abstract class BaseAssetViewModel: BaseViewModel, IBaseAssetViewModel
{
//... just regular properties
}
public class UploadItemViewModel: BaseAssetViewModel, IProgressReporter
{
public UploadItemViewModel(): base()
{
}
private float progress;
public float Progress {
get {
return this.progress;
}
set {
this.progress = value;
this.RaisePropertyChanged(() => Progress);
}
}
}
项目的视图继承自 MvxBindableTableViewCell 并具有以下属性:
private float progress;
public float ProgressMarker {
get {
return progress;
}
set {
progress = value;
// change progressbar or textfield here
}
}
tableviewcell 通过 BindingText 绑定到UploadItemViewModel:
public const string BindingText = @"ProgressMarker Progress, Converter=Float;";
UploadListViewModel 的 sn-p 中提到的 Uploader 类实现了一个尝试在 IProgressReporter 上设置进度的私有方法。
float progressValue;
void SetProgress (float newvalue)
{
progressValue = newvalue;
this.dispatcher.InvokeOnMainThread (delegate {
if (ProgressReporter != null)
ProgressReporter.Progress = progressValue;
});
}
在第一次查看列表期间,我可以看到 ViewModel 和 View 中的属性都被击中,但是当我通过接口 IProgressReporter 使用 Progress 中的新值更新 ViewModel 时,tableviewcell 中的 View没有更新,也没有调用该属性。
我做错了什么或者我在这里错过了什么?
更新:检查此问题的答案。
【问题讨论】:
-
您可以发布更多代码吗?也许是一个要点,包括列表中项目的类以及包含该列表的 ViewModel 的位。另外,我在这里对
Mode=TwoWay位感到困惑 - 只是检查一下我没有误解你在问什么。 -
我用更多代码更新了我的问题。希望现在更清楚了。我删除了
Mode=TwoWay部分,因为那是一些测试的残余。应该是OneWay;从 ViewModel 到 View。 -
谢谢 - 我看不出有什么问题。明天我要尝试复习(但时间对我不利)
-
我能问一件事吗?你能检查单元格的 ProgressMarker
set没有被调用吗?例如给它添加一些痕迹。我能想到的唯一long shot是SetNeedsDisplay()不足以导致重绘(这通常用于自定义Draw方法?) -
我在 ProgressMarker 的
set中添加了一个跟踪,它表明它仅在初始查看期间被调用。我还在UploadItemViewModel的Progress 的set中添加了一个跟踪,它得到了很好的更新,但视图没有得到更新。看起来属性更改的传播未完成或绑定不同步?确实,SetNeedsDisplay()仅用于自定义绘图的重绘,所以我删除了它。
标签: xamarin.ios mvvmcross