You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 18:03:02