c# - 使用 ProgressBar 监控 SQL 查询的执行进度,如果 sql 表的 field_id 增加 1 则更新进度条百分比
问题描述
我完全不知道如何实现这一点。在 StackOverflow 上搜索后,我做了一些努力,但这对我来说显然是前所未有的。
为了首先写这个问题,我假设不能根据 sql 查询的进度更新进度条,因为它不知道 sql 查询的进度如何。
首先,我将描述我的概念。我有一个 MainWindow 类,我的应用程序是在其上设计的。在这个 MainWindow 类上,我有一个名为“ Run ”的按钮。单击此按钮时,它会通过调用 7 个存储过程来运行非常耗时的 sql 查询。具体来说,查询大约需要 4 分钟才能执行。所以我最初的想法是创建一个进度条,向用户显示查询的执行进度,而不是冻结应用程序屏幕和 w8 4 分钟。
主窗口类
namespace TestEnvironment
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public static class StringExtensions
{
public static string Args(this string str, params object[] args)
{
return String.Format(str, args);
}
}
public partial class MainWindow : Window
{
private LoginScreen _LoginScreen;
private CreateProjectScreen _CreateProjectScreen;
public MainWindow(LoginScreen loginscreen, CreateProjectScreen createprojectscreen)
{
InitializeComponent();
_LoginScreen = loginscreen; //2nd window
_CreateProjectScreen = createprojectscreen; //3rd window
}
private void RunCalculationsButton_Click(object sender, RoutedEventArgs e)
{
try
{
Application.Current.Dispatcher.Invoke((Action)delegate {
ProgressBarTemplate win_progressbar = new ProgressBarTemplate();
win_progressbar.Show();
}); //Added the Application.Current Dispatcher because of the STA thread error
//Some extra code after the progress-bar is completed.
//...//
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
}
ProgressBarTemplate 窗口类
using System.Windows;
using System.ComponentModel;
using System.Threading;
using System;
using System.IO;
using System.Data.SqlClient;
namespace TestEnvironment
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class ProgressBarTemplate : Window
{
private CreateProjectScreen _CreateProjectScreen;
private LoginScreen _LoginScreen;
public ProgressBarTemplate()
{
InitializeComponent();
}
public static int RunCalculationsMethod(string connectionstring, string foldername)
{
bool exists = Directory.Exists(foldername);
if (!exists)
{
Directory.CreateDirectory(foldername);
}
try
{
using (SqlConnection sqlConnection = new SqlConnection(connectionstring))
{
var calculations_query = String.Format(
"EXEC [dbo].[procedure_1]; \n" +
"EXEC [dbo].[procedure_2]; \n" +
"EXEC [dbo].[procedure_3] " + "'{0}', " + "';' " + ";\n" +
"EXEC [dbo].[procedure_4] " + "'{0}', " + "';' " + ";\n" +
"EXEC [dbo].[procedure_5]; \n" +
"EXEC [dbo].[procedure_6] " + "'{0}', " + "';' " + ";\n" +
"--EXEC [dbo].[procedure_7]; \n" +
"--EXEC [dbo].[procedure_8] " + "'{0}', " + "';' " + ";\n" +
"EXEC [dbo].[procedure_9]"
, foldername);
using SqlCommand sqlCommand = new SqlCommand(calculations_query, sqlConnection);
sqlConnection.Open();
sqlCommand.CommandTimeout = 60 * 10;
int NumbderOfRecords = sqlCommand.ExecuteNonQuery();
return NumbderOfRecords;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return -100;
}
}
private void Window_ContentRendered(object sender, EventArgs e)
{
try
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
int IsSuccessful = RunCalculationsMethod("Server=localhost;Database=TestProgressBarDB;Integrated Security=SSPI", String.Format("C:\\folder_test\\"));
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbStatus.Value = e.ProgressPercentage;
}
void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This is called on the UI thread when the DoWork method completes
// so it's a good place to hide busy indicators, or put clean up code
try
{
this.Close();
MessageBox.Show("DQ Calculations completed successfully", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OKCancel, MessageBoxImage.Error);
}
}
}
}
进度条 xaml
<Window x:Class="TestEnvironment.ProgressBarTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
Title="ProgressBarTemplate"
Height="100"
Width="300"
ContentRendered="Window_ContentRendered"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
BorderBrush="Black"
BorderThickness="1">
<Border Margin="1,1,1,1" BorderBrush="Black" BorderThickness="0.5">
<Grid Margin="20,10,10,10" Focusable="False">
<ProgressBar
Style="{StaticResource MaterialDesignLinearProgressBar }"
Minimum="0"
Maximum="100"
Name="pbStatus"
Value="75"
Height="15"
Margin="0,10,0,0"
Foreground="Green"
Background="LightGray"
BorderBrush="LightGray"
Focusable="False"
Padding="2"/>
<TextBlock Text="{Binding ElementName=pbStatus, Path=Value, StringFormat={}{0:0}%}"
Style="{StaticResource MaterialDesignButtonTextBlock}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="13"
FontWeight="Medium"
Foreground="Black"
Margin="0,7,0,0"/>
</Grid>
</Border>
</Window>
这是我目前正在运行的代码。但是,即使我的查询开始正确执行并显示进度条,进度百分比也不会改变。它停留在 75%(默认 xaml 文本添加到我的进度条)4 分钟,直到完成。
我的目标是首先使进度条工作(意思是改变百分比值)。第二个目标是根据问题标题中所述的自定义语句更改栏的进度。
每 5 秒检查一次 SQL 日志表,只有当 step 的 field_id 增加 1 时,才会更新进度条 0.88%。0.88% 是步数/100% = 88 步/100。88 步是必要的完成整个查询才能成功。所以查询从 id 1 的第 1 步开始,5 秒后我想检查表,如果 id 为 2 的第 2 步完成,则将进度条增加 0.88%。然后在 5 秒后重新检查 sql 表,如果写入 id 为 3 的步骤 3,则将进度条再更改 0.88%,现在总共 1.76%。这样做直到 100%。
我查询 field_id 所在的 SQL 表
public List<int> GetFieldId(string connectionstring)
{
List<int> fieldid= new List<int>();
using (SqlConnection sqlConnection = new SqlConnection(connectionstring))
{
var query = "SELECT TOP(1) l.LOG_ID FROM LOG_DETAILS l ORDER BY 1 DESC"
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand(query , sqlConnection))
{
using (SqlDataReader reader = sqlCommand.ExecuteReader())
{
while (reader.Read())
{
fieldid.Add(reader.GetInt32(0));
}
reader.Close();
}
sqlCommand.Cancel();
}
}
return fieldid;
}
像这样调用方法
int number_field_id = GetFieldId("Server=localhost;Database=TestProgressBarDB;Integrated Security=SSPI");
因此,每 5 秒执行一次 GetFieldId() 方法,获取顶部的 field_id,如果它从上一次检查(过去 5 秒)增加 1,则进度条将增加 0.88%。
请考虑我写这个问题的努力,因为我试图尽可能清楚地说明问题。
[1 可能的解决方案 - 但不是首选]
因为我知道在查询执行之前我会 w8 4 分钟,所以我可以做类似的事情
void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
(sender as BackgroundWorker).ReportProgress(i);
Thread.Sleep(60*4 + 10); //+10 secs
}
}
但这不是动态的,因为我不知道每次都是 4 分钟。它在我的本地机器上运行 4 分钟。
搜索的相关 SO 问题:
解决方案
推荐阅读
- java - 为什么edittext重新加载listview?
- java - 两个 Java 相关类的最佳实践,例如 Recipe 和 Ingredient
- openlayers - 如何在 Openlayer 中从样式几何生成的任何平行线上单击哪个 lineString
- java - 如何将java程序(log4j2)中的日志索引到elasticsearch
- hibernate - 多次将相同的 JPA 实体映射到其他 JPA 实体
- php - Laravel - 无法从控制器变量到视图
- amazon-web-services - Elastic Beanstalk 部署:UndefinedModelAttributeError
- sql-server - SSIS 包中的 FTP 任务未执行
- javascript - 在 Angular 中使用 `fetch`
- reactjs - 来自 github 的 react-native 链接库