Wpf BackGroundWorker在执行时给出线程错误

问题描述 投票:0回答:1

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




}

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

enter image description here

[抱歉,它是法文,但它说:“由于其他胎面拥有它,因此胎面不能访问该对象。有人能帮我吗 ?谢谢

wpf backgroundworker
1个回答
0
投票

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

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

可使SQL查询更具可读性
© www.soinside.com 2019 - 2024. All rights reserved.