在WPF应用程序中,您好,我有一个执行一些时间的sql查询,并且我想用进度条实现BackgroundWorker,以便用户可以看到它何时完成。
这里是XAML部分:
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ProgressBar x:Name="BgProgBar" Margin="5"/>
<TextBlock x:Name="Perc_TB" HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Path=Value,ElementName=BgProgBar}"/>
</Grid>
这是后面的代码中的BackGroundWorker:
public partial class Supp_Stocks : Page
{
private string _user = Settings.Default.User;
private DataTable dt;
SqlConnection conn;
SqlCommand comm;
SqlConnectionStringBuilder connStringBuilder;
BackgroundWorker Bg = new BackgroundWorker();
public Supp_Stocks()
{
InitializeComponent();
ConnectToDB();
Bg.DoWork += Bg_DoWork;
Bg.ProgressChanged += Bg_ProgressChanged;
Bg.WorkerReportsProgress = true;
}
#region BackGroundWorker
private void Bg_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BgProgBar.Value = e.ProgressPercentage;
}
private void Bg_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0; i < 100; i++)
{
try
{
comm = new SqlCommand("select STOCK_ENT.ENT_ID,ENT_DATE_ENT,ENT_NUMPAL,CLI_NOM,ART_LIBELLE1,ENT_PICKING,SUM(det_pnet)" +
" as POIDS_NET from STOCK_DET, STOCK_ENT, CLIENTS, FICHES_ARTICLES, MVTS_SEQUENCE where SEQ_STATUT <> 'V' and" +
" STOCK_ENT.ENT_ID = STOCK_DET.ENT_ID and STOCK_ENT.ENT_PROP = CLI_CODE and STOCK_ENT.ART_CODE = FICHES_ARTICLES.ART_CODE" +
" and STOCK_ENT.ENT_ID = MVTS_SEQUENCE.ENT_ID group by STOCK_ENT.ENT_ID, ENT_DATE_ENT, ENT_NUMPAL, CLI_NOM, ART_LIBELLE1, ENT_PICKING order by ART_LIBELLE1", conn);
SqlDataAdapter dap = new SqlDataAdapter(comm);
dt = new DataTable();
dap.Fill(dt);
Stocks_DT.ItemsSource = dt.DefaultView;
Bg.ReportProgress(i);
}
catch (Exception ex)
{
var stList = ex.StackTrace.ToString().Split('\\');
Messages.ErrorMessages($"ERREUR : \n{ex.Message}\n\nException at : \n{stList[stList.Count() - 1]}");
}
}
}
private void GenerateStk_Btn_Click(object sender, RoutedEventArgs e)
{
Bg.RunWorkerAsync();
}
#endregion
private void ConnectToDB()
{
connStringBuilder = new SqlConnectionStringBuilder
{
DataSource = @"VM-VISUALSTORE\SQLEXPRESS,1433",
InitialCatalog = "GSUITE",
Encrypt = true,
TrustServerCertificate = true,
ConnectTimeout = 30,
AsynchronousProcessing = true,
MultipleActiveResultSets = true,
IntegratedSecurity = true,
};
conn = new SqlConnection(connStringBuilder.ToString());
comm = conn.CreateCommand();
}
}
但是执行代码时会返回错误:
[抱歉,它是法文,但它说:“由于其他胎面拥有它,因此胎面不能访问该对象。有人能帮我吗 ?谢谢
您没有说代码中的哪一行引发了错误,但是我很确定这是这一行,对吧?
Stocks_DT.ItemsSource = dt.DefaultView;
Stocks_DT
是您窗口上的控件,对吧?
这就是问题的根源。如错误所述,您只能从UI线程(主线程)访问UI元素。由于您正在后台线程上运行以上代码,因此会引发此异常。
相反,您需要将查询结果传递回主线程。然后将其分配给Stocks_DT.ItemsSource
。我建议使用DoWorkEventArgs.Result
属性。我建议使用DoWorkEventArgs.Result
作为结果,因此代码应为DataTable
。您可以从e.Result = dt
事件访问Result
。
以上内容可以解决异常,但是我认为还有很多其他事情,我纯粹出于帮助您的目的而应该在您的代码中进行介绍。
首先,您似乎要对相同的确切查询进行100次循环,而没有进行任何更改。这似乎是在浪费时间,因为您只会获得100次相同的结果。如果是这种情况,您可能根本不需要进度条。
[其次,通常认为最佳做法是在需要时打开一个新的BackgroundWorker.RunWorkerCompleted
,并在完成时关闭它,而不是在程序/窗口的整个生命周期中保持打开状态。当您进入多线程时尤其如此。您可以在SqlConnection
中找到更多信息。创建这些连接时,应将其包含在this question语句中。
第三,C#支持多行字符串,如using
中所示。使用此方法,通过消除所有的this question