Xamarin.Forms中EventToCommandBehavior绑定RelativeSource崩溃求助
在Xamarin.Forms的XAML代码中,我给Editor控件添加了EventToCommandBehavior,将Focused事件绑定到ViewModel的CheckEditorViewCommand,用RelativeSource指定AncestorType为view:SurveyViewModel。但打开页面时应用直接崩溃,移除这段代码后页面能正常运行。我知道问题出在绑定方式上,但不清楚正确的实现方法。
崩溃日志如下:
01-14 07:50:43.611 F/mono-rt (28519): [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Operation is not valid due to the current state of the object.
01-14 07:50:43.611 F/mono-rt (28519): at Xamarin.Forms.Binding.ApplyRelativeSourceBinding (Xamarin.Forms.BindableObject targetObject, Xamarin.Forms.BindableProperty targetProperty) [0x00041] in D:\a\1\s\Xamarin.Forms.Core\Binding.cs:158
01-14 07:50:43.611 F/mono-rt (28519): at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__7_0 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1021
01-14 07:50:43.611 F/mono-rt (28519): at Android.App.SyncContext+<>c__DisplayClass2_0.b__0 () [0x00000] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:36
01-14 07:50:43.611 F/mono-rt (28519): at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36
01-14 07:50:43.611 F/mono-rt (28519): at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-33/mcw/Java.Lang.IRunnable.cs:84
01-14 07:50:43.611 F/mono-rt (28519): at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V (_JniMarshal_PP_V callback, System.IntPtr jnienv, System.IntPtr klazz) [0x00005] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:22
01-14 07:50:43.611 F/mono-rt (28519): at (wrapper native-to-managed) Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(intptr,intptr)
相关代码:
<Editor Text="{Binding OptionText}"> <Editor.Behaviors> <xct:EventToCommandBehavior EventName="Focused" Command="{Binding CheckEditorViewCommand,Source={RelativeSource AncestorType={x:Type view:SurveyViewModel}}}" /> </Editor.Behaviors> </Editor>
崩溃的核心是**RelativeSource的AncestorType不能直接指定ViewModel类型**。RelativeSource是用来在视觉树(Visual Tree)中查找父级UI元素的,而ViewModel不属于视觉树的一部分,它是页面的BindingContext,用这种方式查找必然失败,触发InvalidOperationException。
方案1:直接绑定(推荐)
从你的代码看,Editor的Text已经绑定了ViewModel的OptionText,说明Editor的BindingContext就是SurveyViewModel,不需要额外指定Source,直接绑定命令即可:
<Editor Text="{Binding OptionText}"> <Editor.Behaviors> <xct:EventToCommandBehavior EventName="Focused" Command="{Binding CheckEditorViewCommand}" /> </Editor.Behaviors> </Editor>
方案2:通过页面元素获取BindingContext
如果Editor处于嵌套布局或模板中,导致自身BindingContext不是ViewModel,可以通过查找视觉树中的父级页面(比如ContentPage)来获取它的BindingContext:
<Editor Text="{Binding OptionText}"> <Editor.Behaviors> <xct:EventToCommandBehavior EventName="Focused" Command="{Binding BindingContext.CheckEditorViewCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}" /> </Editor.Behaviors> </Editor>
方案3:使用x:Reference指定页面
给页面设置x:Name,通过x:Reference直接绑定页面的BindingContext:
<ContentPage x:Name="SurveyPage" ...> <!-- 其他页面内容 --> <Editor Text="{Binding OptionText}"> <Editor.Behaviors> <xct:EventToCommandBehavior EventName="Focused" Command="{Binding BindingContext.CheckEditorViewCommand, Source={x:Reference SurveyPage}}" /> </Editor.Behaviors> </Editor> </ContentPage>
内容的提问来源于stack exchange,提问作者Winteriscoming

