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

如何让WPF应用等待UI线程完全加载窗口后再执行后续处理?

解决方案

核心思路是放弃固定时长的定时器,改用WPF元素的Loaded事件监听窗口/视图的加载完成状态,确保所有视图完全渲染后再启动快照逻辑。

修改后的代码实现

private int _loadedViewsCount;
private int _totalViewsToLoad;

protected override void DoStartCapture()
{
    try
    {
        m_dispatcherTimers = new List<DispatcherTimer>();
        _loadedViewsCount = 0;
        _totalViewsToLoad = m_mimicGroupsToCapture.Sum(g => g.Mimics.Count);

        // 先创建所有定时器但暂不启动
        foreach (var mimicGroup in m_mimicGroupsToCapture)
        {
            var dispatcherTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(Convert.ToInt32(mimicGroup.CaptureIntervalInSeconds)),
                Tag = mimicGroup
            };
            dispatcherTimer.Tick += M_mainDispatcherTimer_Tick;
            m_dispatcherTimers.Add(dispatcherTimer);
        }

        // 打开视图并绑定加载完成事件
        foreach (var mimicGroup in m_mimicGroupsToCapture)
        {
            foreach (var mimic in mimicGroup.Mimics)
            {
                var view = OpenView(mimic.View, 2);
                if (view is FrameworkElement frameworkElement)
                {
                    // 绑定Loaded事件,触发后解绑避免重复计数
                    frameworkElement.Loaded += OnViewLoaded;
                }
                else
                {
                    // 如果OpenView不返回视图对象,通过服务获取并绑定事件
                    Dispatcher.BeginInvoke(DispatcherPriority.Background, () =>
                    {
                        var targetView = ViewsIntegrationService.GetOpenViews()
                            .FirstOrDefault(v => v.ViewId == mimic.View.ViewId); // 假设视图有唯一标识
                        if (targetView is FrameworkElement elem)
                        {
                            elem.Loaded += OnViewLoaded;
                        }
                        else
                        {
                            Trace.TraceWarning($"Failed to locate view for {mimic.View.Name}");
                            MarkViewAsLoaded();
                        }
                    });
                }
            }
        }

        // 处理无视图需要加载的情况
        if (_totalViewsToLoad == 0)
        {
            m_openViews = ViewsIntegrationService.GetOpenViews();
            StartAllTimers();
            return;
        }

        // 添加超时机制,防止因视图加载失败卡住流程
        var timeoutTimer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(2) };
        timeoutTimer.Tick += (s, e) =>
        {
            timeoutTimer.Stop();
            if (_loadedViewsCount < _totalViewsToLoad)
            {
                Trace.TraceWarning($"View loading timed out. Loaded {_loadedViewsCount}/{_totalViewsToLoad} views");
            }
            m_openViews = ViewsIntegrationService.GetOpenViews();
            StartAllTimers();
        };
        timeoutTimer.Start();
    }
    catch (Exception ex)
    {
        Trace.TraceError("View Capture Service error. Exception: " + ex.Message);
        StopCapture();
        throw;
    }
}

private void OnViewLoaded(object sender, RoutedEventArgs e)
{
    if (sender is FrameworkElement frameworkElement)
    {
        frameworkElement.Loaded -= OnViewLoaded; // 解绑事件避免重复触发
    }
    MarkViewAsLoaded();
}

private void MarkViewAsLoaded()
{
    _loadedViewsCount++;
    if (_loadedViewsCount == _totalViewsToLoad)
    {
        m_openViews = ViewsIntegrationService.GetOpenViews();
        StartAllTimers();
    }
}

private void StartAllTimers()
{
    foreach (var timer in m_dispatcherTimers)
    {
        timer.Start();
    }
}

关键修改说明

  1. 改用Loaded事件跟踪加载状态
    WPF的Loaded事件会在元素的可视化树构建完成、布局计算和渲染全部完成后触发,是判断窗口完全加载的可靠依据,替代原来的固定时长定时器,避免因加载时长波动导致快照提前执行。

  2. 统计视图加载进度
    先计算需要加载的视图总数,每一个视图触发Loaded事件后就计数,当计数等于总数时,再启动所有快照定时器。

  3. 兼容OpenView的两种返回情况

    • 如果OpenView直接返回视图对象,直接绑定Loaded事件
    • 如果OpenView不返回对象,通过ViewsIntegrationService获取视图,并利用Dispatcher.BeginInvoke确保在UI队列的后续环节获取到已打开的视图。
  4. 添加超时机制
    防止因个别视图加载失败导致流程卡住,设置2分钟超时,超时后强制启动快照逻辑并记录警告日志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:43:17