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

Xamarin中Timer Elapsed事件未触发 警告视图无法自动隐藏问题

问题根因

这个问题和INotifyPropertyChanged接口完全无关,该接口仅用于数据绑定场景下的属性变更通知,你是直接在代码后台操作控件自身属性,本身不需要实现该接口。
真正的问题出在你使用的System.Timers.Timer运行机制上:

  • System.Timers.Timer的Elapsed事件默认在线程池的工作线程触发,而所有跨平台UI框架(包括MAUI/Xamarin.Forms)都有强制要求:UI元素的属性修改、渲染操作必须在UI主线程执行,非主线程直接操作UI属性会被静默拦截,不会抛显性异常,也不会生效。你这里的Elapsed事件实际上已经正常触发了,只是回调里修改IsVisible = false的操作因为跨线程被拦截,才会出现警告框一直不消失的现象。
  • 你当前的Timer逻辑还有个隐藏缺陷:如果用户在警告显示的5秒内多次触发ShowWarning,现有逻辑不会重置计时器,会出现警告显示时长不足5秒就提前隐藏,或者多次触发回调的异常表现。
修复方案

有两种可行的修复方式,优先推荐第二种,更适配UI场景:

方案1:保留现有Timer,回调中切换到UI线程执行UI操作

只需要修改Elapsed事件的回调逻辑,把UI操作切到主线程执行,同时补充计时器重置逻辑即可:

private void SetEvents()
{
    timer.Elapsed += (object sender, ElapsedEventArgs e) => { 
        // 切换到UI主线程修改控件属性
        MainThread.BeginInvokeOnMainThread(() =>
        {
            this.IsVisible = false;
        });
        timer.Stop();
    };
    ShowWarning += () => { 
        this.IsVisible = true; 
        // 每次触发警告先重置计时器,保证每次都显示满5秒
        timer.Stop();
        timer.Start();
    };
}

方案2:替换为UI线程专属的DispatcherTimer(推荐)

直接使用UI框架自带的IDispatcherTimer,这个计时器的Tick事件天然就在UI主线程触发,完全不需要手动处理跨线程问题,也不会出现你现在遇到的bug,是UI场景下做延时操作的最优选择。
替换后的完整类代码如下:

public partial class ValidExpressionWarning : ContentView
{
    public static ValidExpressionWarning Instance;
    public Action ShowWarning;
    private readonly IDispatcherTimer _warningTimer;

    public ValidExpressionWarning()
    {
        InitializeComponent();
        Instance = this;
        // 初始化UI线程计时器
        _warningTimer = Dispatcher.CreateTimer();
        _warningTimer.Interval = TimeSpan.FromSeconds(5);
        BindEvents();
    }

    private void BindEvents()
    {
        _warningTimer.Tick += (_, _) =>
        {
            IsVisible = false;
            _warningTimer.Stop();
        };
        ShowWarning += () =>
        {
            IsVisible = true;
            // 重置计时,保证每次触发都显示满5秒
            _warningTimer.Stop();
            _warningTimer.Start();
        };
    }
}

补充说明:如果你用的是Xamarin.Forms而非.NET MAUI,IDispatcherTimer对应的API是Device.StartTimer,逻辑是一致的,都是在UI线程执行计时回调。

内容的提问来源于stack exchange,提问作者youngcoder126

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:12:26