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

WPF执行SQL查询更新UI时ProgressRing不显示问题求助

问题:WPF中MahApps Metro ProgressRing在SQL查询时无法显示

我正在开发WPF应用,使用MahApps Metro控件及主题。需求是在执行多SQL查询并动态创建Tab页更新UI时,显示ProgressRing加载指示器,但该指示器无法正常显示。用Task.Delay替代SQL查询逻辑时,ProgressRing能正常显示。

相关代码

XAML代码

<mah:ProgressRing x:Name="loadingIndicator" Grid.RowSpan="2" 
                  Foreground="{DynamicResource AccentColorBrush}"
                  IsActive="{Binding IsLoading}" />

按钮点击事件代码

private async void ExecuteButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    if (DataContext is ExecutionWindowViewModel viewModel)
    {
        if (outputTab.Items.Count > 0)
        {
            outputTab.Items.Clear();
        }
        var selectedDatabases = viewModel.Databases.Where(x => x.IsSelected == true).ToList();
        viewModel.IsLoading = true;
        await Task.Run(() =>
        {
            this.Dispatcher.Invoke(new Action(() =>
            {
                foreach (var database in selectedDatabases)
                {
                    TabItem tabItem = new TabItem();
                    tabItem.Header = database.DBShortName;
                    DataGrid sqlOutput = new DataGrid();
                    sqlOutput.AutoGenerateColumns = true;
                    sqlOutput.IsReadOnly = true;
                    var test = viewModel.SQLQueryExecution(database.ConnectionString);
                    sqlOutput.ItemsSource = viewModel.SQLQueryExecution(database.ConnectionString).AsDataView();
                    tabItem.Content = sqlOutput;
                    outputTab.Items.Add(tabItem);
                }
            }));
        });
        viewModel.IsLoading = false;
    }
}

ViewModel中IsLoading属性实现

private bool _isLoading = false;
public bool IsLoading
{
    get => _isLoading;
    set
    {
        if (_isLoading != value)
        {
            _isLoading = value;
            OnPropertyChanged(nameof(IsLoading));
        }
    }
}

问题原因与解决方案

核心原因

你的代码把所有耗时操作(SQL查询+UI创建)都通过Dispatcher.Invoke强行塞回UI线程执行,导致UI线程被完全阻塞,根本没时间更新和渲染ProgressRing。Task.Run虽然启动了后台线程,但后台线程里没有执行任何实际逻辑,直接把所有操作抛回UI线程,等于整个流程还是在UI线程同步执行,ProgressRing自然无法显示。

修复方案

要把耗时的SQL查询逻辑放在后台线程,仅把**UI相关操作(创建Tab、DataGrid等)**通过Dispatcher切回UI线程执行,这样UI线程不会被阻塞,能正常渲染加载指示器。

修改后的按钮点击事件代码:

private async void ExecuteButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    if (DataContext is ExecutionWindowViewModel viewModel)
    {
        if (outputTab.Items.Count > 0)
        {
            outputTab.Items.Clear();
        }
        var selectedDatabases = viewModel.Databases.Where(x => x.IsSelected == true).ToList();
        viewModel.IsLoading = true;

        await Task.Run(() =>
        {
            foreach (var database in selectedDatabases)
            {
                // 耗时的SQL查询放在后台线程执行,不占用UI线程
                var queryResult = viewModel.SQLQueryExecution(database.ConnectionString).AsDataView();
                
                // 仅UI操作通过Dispatcher切回UI线程
                this.Dispatcher.Invoke(() =>
                {
                    TabItem tabItem = new TabItem();
                    tabItem.Header = database.DBShortName;
                    DataGrid sqlOutput = new DataGrid();
                    sqlOutput.AutoGenerateColumns = true;
                    sqlOutput.IsReadOnly = true;
                    sqlOutput.ItemsSource = queryResult;
                    tabItem.Content = sqlOutput;
                    outputTab.Items.Add(tabItem);
                });
            }
        });

        viewModel.IsLoading = false;
    }
}

额外优化建议

  1. 避免在后台循环里频繁调用Dispatcher.Invoke,可以先在后台线程完成所有SQL查询,把结果收集后一次性切回UI线程创建所有Tab页,减少UI线程的切换开销。
  2. 建议将UI元素的创建逻辑从事件处理中剥离,放在ViewModel或专门的UI服务类中,符合MVVM设计思想。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:03:01