原因——为什么需要谨慎使用x:Bind?
在实际开发中发现,使用它会导致VM回收不及时,可能导致内存泄漏。
那为何要在项目中使用它呢?
因为:{x:Bind} 标记扩展(Windows 10 的新增功能)是 {Binding} 的替代方法。 {x:Bind} 比 {Binding} 运行的时间更少,内存更少,并支持更好的调试。
详细可以参考:xBind 标记扩展 - UWP applications | Microsoft Learn
如何解绑绑定?
Binding解绑
说到Binding,WPF和UWP、以及到当下的WINUI都支持,而x:Bind仅UWP和WINUI目前支持。
使用Binding,在Page或Window生命终结时,一般只需要设置将DataContext置空即可;若在Page或Window的后台代码中设置了VM,那么最好也在设置DataContext时同时将VM置空。
如此即可将使用Binding的所有绑定全部解绑,如下所示;此建议在Page或Window的Unloaded事件中进行相应的处理。
this.DataContext = null; this.ViewModel = null;
当然,若使用Frame进行导航时,也可以在重写OnNavigatingFrom方法。
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { base.OnNavigatingFrom(e); this.DataContext = null; this.ViewModel = null; }
但不建议如此,原因是OnNavigatingFrom方法在Unloaded事件前执行,在OnNavigatingFrom方法中将VM置为null后,若需要在Unloaded时执行某个Command,那么这个Command将失灵。
x:Bind解绑
它的解绑,相对于Binding而言需要多做几个几步。
在将DataContext置为null前,将Bindings全部解除跟踪;Bindings为在使用x:Bind时生成。
this.Bindings.StopTracking(); this.DataContext = null; this.ViewModel = null;
同时,在使用x:Bind进行绑定的Command、Behavior、文本的双向绑定等等最好也手动清除掉;
在使用MVVM Toolkit8.2.2中的源生成器标记了Command和绑定属性后,会导致VM即使被置空,也会导致VM不能被正常回收;
那么若不断需要进入某个Page就会实例化一个这个Page的VM,然后操作完退出这个Page,再进入这个Page,又会实例化这个Page的VM,最终导致这个Page的VM不能被回收释放;同时这个Page的实例也不会被正常回收。出现如下的情况:
上图中VM之所以未被正常回收释放,就是因为Behavior引用中使用了x:Bind。
使用x:Bind的问题代码如下:
<interactivity:Interaction.Behaviors> <core:EventTriggerBehavior EventName="Loaded"> <core:InvokeCommandAction x:Name="PageLoadInvoke" Command="{x:Bind ViewModel.QueryUserCommand}" /> </core:EventTriggerBehavior> </interactivity:Interaction.Behaviors>
从实测来看,只要将上述代码中的改为Binding,那么问题解决了,即
<interactivity:Interaction.Behaviors> <core:EventTriggerBehavior EventName="Loaded"> <core:InvokeCommandAction x:Name="PageLoadInvoke" Command="{Binding QueryUserCommand}" /> </core:EventTriggerBehavior> </interactivity:Interaction.Behaviors>
当然也可以直接使用 InvokeCommandAction 的Name调用这个Action,直接将它置null,也是可以解决问题的,即
PageLoadInvoke.Command = null;
总结
说了这么多,目前来说由于一些问题,导致使用x:Bind绑定VM中的Command或其它一些绑定属性后,会导致VM回收异常;而使用Binding反倒没有这个问题,虽然MS的文档说使用x:Bind性能更好,但它却可能会导致内存泄漏,因此暂时还是以Binding进行绑定为好,待后续WINUI和MVVMToolkit解决这一问题后,再考虑使用x:Bind吧。