我将MvvmCross与MonoDroid一起使用。
在 View 模型的计时器中,每分钟我都会调用RaisePropertyChanged("MinutesRemaining")
-MinutesRemaining
是一个整数,指定直到当前条目结束为止的持续时间(以分钟为单位)(是的,这在UI线程上被调用!)。
使用MvvmCross将MinutesRemaining
绑定(bind)到TextView
。
在从Xamarin更新4.10.1
之前,该应用程序将完全崩溃,并且不会在跟踪记录上显示任何错误消息-它现在在调试时正确中断,在调用PropertyChanged
事件时给出以下错误:
MvxBind:Error:281.24 Problem seen during binding execution for binding Text for MinutesRemaining - problem ArgumentException: 'jobject' must not be IntPtr.Zero.
Parameter name: jobject
at Android.Runtime.JNIEnv.CallVoidMethod (IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00010] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:499
at Android.Widget.TextView.set_TextFormatted (ICharSequence value) [0x00034] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/platforms/android-14/src/generated/Android.Widget.TextView.cs:1814
at Android.Widget.TextView.set_Text (System.String value) [0x00013] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/9d03ce3e/source/monodroid/src/Mono.Android/platforms/android-14/src/generated/Android.Widget.TextView.cs:1823
at Cirrious.MvvmCross.Binding.Droid.Target.MvxTextViewTextTargetBinding.SetValueImpl (System.Object target, System.Object toSet) [0x00000] in <filename unknown>:0
at Cirrious.MvvmCross.Binding.Bindings.Target.MvxConvertingTargetBinding.SetValue (System.Object value) [0x00000] in <filename unknown>:0
at Cirrious.MvvmCross.Binding.Bindings.MvxFullBinding.UpdateTargetFromSource (System.Object value) [0x00000] in <filename unknown>:0
第一次正确绑定(bind)-仅在随后的
RaisePropertyChanged
调用中会发生这种情况。相同的代码也适用于Windows 8和Windows Phone。更新
在上述方案所使用的适配器中使用JavaFinalise可以解决此问题(在此处找到:MVVMCross Binding Crashes Android Application)。我现在遇到的问题是相同的结果,但是适配器中的第一个 View 绑定(bind)到父 View 模型中的属性(而不是项目)。
用于绑定(bind)的代码如下:
public class SubjectFilterAdapter : MvxAdapter {
private EntityListFragment<TEntity, TViewModel> _owner;
public SubjectFilterAdapter(Context context, EntityListFragment<TEntity, TViewModel> owner) : base(context, (IMvxAndroidBindingContext)owner.BindingContext) {
_owner = owner;
}
protected override View GetBindableView(View convertView, object dataContext, int templateId) {
var view = base.GetBindableView(convertView, dataContext, templateId);
if (templateId == ItemTemplateId && GetPosition(dataContext) == 0) {
var set = _owner.CreateBindingSet<EntityListFragment<TEntity, TViewModel>, TViewModel>();
set.Bind(view.FindViewById<TextView>(Resource.Id.SelectedScheduleText))
.To(x => x.SelectedScheduleText).WithClearBindingKey("SelectedScheduleTextFilterBinding");
set.Apply();
}
return view;
}
protected override void JavaFinalize() {
if (this.BindingContext != null)
this.BindingContext.ClearAllBindings();
base.JavaFinalize();
}
}
首先,它可以正常工作(对于前几对更改),但是之后,会引发上述异常。使用MvvmCross
3.0.14-beta3
。谢谢!
最佳答案
通过将listitem/单元绑定(bind)上下文与父上下文混合在一起,您将进入一个非常高级的领域。
为了帮助您解释/调试正在发生的事情,您需要了解所有父级生命周期,listitem/单元生命周期以及相应的MvvmCross绑定(bind)上下文的生命周期。
在父级生命周期级别上,这通常是Android的Activity
或Fragment
。为了简单起见,我将在此答案的其余部分中使用Activity
。
此Activity
具有几个关键的生命周期事件
OnCreate
仅在首次启动Activity
时被调用一次OnDestroy
时,才会调用Activity
。 MvvmCross拦截这些事件,并:
OnCreate
中的ViewModel
设置为Activity
的DataContext
。用户代码-通常在SetContentView
中夸大的Xml代码-然后创建绑定(bind)。这些绑定(bind)存储在BindingContext
Activity
中OnDestroy
中的BindingContext
中的所有绑定(bind)在我们感兴趣的用户界面中,
Activity
拥有ListView
,并且ListView
为其设置了Adapter
。在这种情况下,DataContext
的ListView
及其Adapter
与它的父级相同。在
ListView
的生命周期内,列表可能需要显示很多项目。随时显示的项目可能会更改-既由于用户的触摸操作,也由于 View 模型的更改。要显示这些项目,ListView
向Adapter
询问View
。对于每个项目,它显示Adapter
提供了View
,并且这些View
可以重复使用(使用convertView
参数)。但是,有时这些View
也不会被重用-在这种情况下,即使在删除Java/Dalvik View
并完成Java处理之后,View对象有时仍可以存在于C#中。MvvmCross截获其
GetView
中的MvxAdapter
调用。对于每个调用,它不仅返回View
,而且还返回MvxListItemView
。这是一个添加了View
的BindingContext
-并允许MvvmCross用户将每个MvxListItemView
绑定(bind)到其列表项DataContext
。重用
MvxListItemView
时,对于MvvmCross只需更改其DataContext
就很简单。当不重新使用
MvxListItemView
时-从UI中删除它,然后将JavaFinalize
d-MvvmCross截获OnDetachedFromWindow
事件,并使用此事件将DataContext
切换为null
。它是在OnDetachedFromWindow
而不是JavaFinalize
上执行此操作的,因为可以确保在UI线程上进行Window调用,并且(对我而言)感觉更干净了。请注意,此行为在最近的发行版中已发生了细微变化-但以上说明仅适用于v3.0.14
有了适当的背景,您当前正在尝试做的是在
ListItemView
的BindingContext
内为Activity
的内容创建一个绑定(bind)。这意味着绑定(bind)实际上并没有对
ListItemView
的生命周期有很好的了解-因此,即使从屏幕上删除了ListItemView
并完成了绑定(bind),该绑定(bind)仍可以保持 Activity 状态。要解决此问题...
JavaFinalize
有点“顽皮”,因为它在Activity
的Finalize
期间清除了父Adapter
的BindingContext。这样做也许可以,但实际上不是必须的-Activity
自己的OnDestroy
应该可以处理该问题。 关于android - 在MonoDroid中设置textview的文本时,“jobject”不得为IntPtr.Zero,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19974267/