如何在Uno WASM中实现轮播幻灯片?DispatcherTimer失效如何解决
问题根因
Uno Platform WASM 原生支持DispatcherTimer,你的代码逻辑本身没有问题,失效通常是以下两个原因导致:
timer未定义为页面类的成员变量,WASM运行时GC会在SlideShowPageLoaded方法执行结束后回收无强引用的timer实例,导致Tick事件不再触发- 部分Uno版本中WASM下UI绑定更新需要显式调度到UI线程执行
修复原代码方案
首先将timer定义为页面类的全局成员,保持强引用避免被GC回收,同时调整Tick事件逻辑显式调度UI更新:
// 页面类内定义成员 private DispatcherTimer timer; public void SlideShowPageLoaded(object sender, RoutedEventArgs args) { vm.URL = vm.SlideList[CurrentIndex].URL; timer = new DispatcherTimer(); timer.Tick += dispatcherTimer_Tick; timer.Interval = new TimeSpan(0, 0, this.Interval); timer.Start(); } private void dispatcherTimer_Tick(object sender, object e) { this.GetNextIndex(); try { // 显式调度到UI线程更新绑定,兼容WASM平台 DispatcherQueue.TryEnqueue(() => { vm.URL = vm.SlideList[CurrentIndex].URL; }); } catch (Exception ex) { Debug.WriteLine(ex.Message); } }
同时确认你的ViewModel中URL属性已正确实现INotifyPropertyChanged接口,属性变更时能触发通知。
替代方案1:使用PeriodicTimer(推荐,.NET 6+全平台兼容)
PeriodicTimer是.NET 6引入的线程安全定时器,在WASM下表现更稳定,代码示例如下:
private PeriodicTimer periodicTimer; private CancellationTokenSource cts = new CancellationTokenSource(); public async void SlideShowPageLoaded(object sender, RoutedEventArgs args) { vm.URL = vm.SlideList[CurrentIndex].URL; periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(this.Interval)); // 后台启动轮播逻辑 _ = RunSlideShowLoop(); } private async Task RunSlideShowLoop() { while (await periodicTimer.WaitForNextTickAsync(cts.Token)) { GetNextIndex(); try { await DispatcherQueue.TryEnqueueAsync(() => { vm.URL = vm.SlideList[CurrentIndex].URL; }); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } } // 页面卸载时释放资源 protected override void OnNavigatedFrom(NavigationEventArgs e) { cts.Cancel(); periodicTimer?.Dispose(); cts.Dispose(); base.OnNavigatedFrom(e); }
替代方案2:WASM专属JS互操作实现定时器(兼容.NET 5及更早版本)
如果项目使用的.NET版本低于6,可以通过WASM JS互操作调用浏览器原生setInterval实现定时器:
private int jsTimerId; // 标注为JS可调用方法 [JSInvokable] public void OnSlideTimerTick() { GetNextIndex(); vm.URL = vm.SlideList[CurrentIndex].URL; } public void SlideShowPageLoaded(object sender, RoutedEventArgs args) { vm.URL = vm.SlideList[CurrentIndex].URL; #if __WASM__ // 调用浏览器原生setInterval,间隔单位为毫秒 var assemblyName = GetType().Assembly.GetName().Name; jsTimerId = (int)Uno.Foundation.WebAssemblyRuntime.InvokeJS( $"setInterval(() => DotNet.invokeMethodAsync('{assemblyName}', '{nameof(OnSlideTimerTick)}'), {Interval * 1000})" ); #else // 其他平台沿用原有DispatcherTimer逻辑 timer = new DispatcherTimer(); timer.Tick += dispatcherTimer_Tick; timer.Interval = new TimeSpan(0, 0, this.Interval); timer.Start(); #endif } // 页面卸载时清除定时器避免内存泄漏 protected override void OnNavigatedFrom(NavigationEventArgs e) { #if __WASM__ Uno.Foundation.WebAssemblyRuntime.InvokeJS($"clearInterval({jsTimerId})"); #else timer?.Stop(); #endif base.OnNavigatedFrom(e); }
内容的提问来源于stack exchange,提问作者Robotuner
相关产品推荐
相关产品推荐

