【问题标题】:BackgroundWorker gives threading error when executingBackgroundWorker 执行时出现线程错误
【发布时间】:2019-10-20 02:28:30
【问题描述】:

在 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();
    }
}

但在执行代码时会返回错误:

对不起,它是法语,但它说“线程无法访问这个对象,因为另一个线程拥有它。

【问题讨论】:

标签: wpf multithreading backgroundworker


【解决方案1】:

您没有说代码中的哪一行引发了错误,但我很确定是这一行,对吧?

Stocks_DT.ItemsSource = dt.DefaultView;

Stocks_DT 是您窗口上的控件,对吧?

这就是问题的根源。正如错误所说,您只能从 UI 线程(主线程)访问 UI 元素。由于您在后台线程上运行上述代码,因此会引发此异常。

相反,您需要将查询结果传递回主线程然后将其分配给Stocks_DT.ItemsSource。我建议使用 DoWorkEventArgs.Result 属性。我建议使用DataTable 作为结果,因此代码为e.Result = dt。您可以通过BackgroundWorker.RunWorkerCompleted 事件访问Result


以上将解决异常,但我觉得我应该在你的代码中复习一些其他的东西,纯粹是为了帮助你。

首先,您似乎将相同的查询循环了 100 次而没有任何更改。这似乎是在浪费时间,因为您只会得到相同的结果 100 次。如果是这种情况,您可能根本不需要进度条。

其次,通常认为最佳做法是在需要时打开一个新的SqlConnection,并在完成时将其关闭,而不是在程序/窗口的整个生命周期内保持一个连接打开。当您进入多线程时尤其如此。您可以在this question 中找到更多信息。创建这些连接时,应将它们包含在 using 语句中。

第三,C#支持多行字符串,如this question所示。使用此方法将通过删除所有"..." + "..." 使SQL 查询更具可读性

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    相关资源
    最近更新 更多