WINUI——WINUI开发中谨慎使用x:Bind

发布于:2025-06-09 ⋅ 阅读:(21) ⋅ 点赞:(0)

原因——为什么需要谨慎使用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吧。