2

以下のコードに示すように、バックグラウンド ワーカー プロセスから Windows フォーム コントロールを更新しようとしています。残念ながら、次のエラーが表示されます。

クロススレッド操作が無効です: コントロール 'richTextBox1' は、それが作成されたスレッド以外のスレッドからアクセスされました。

私が使用しているコードは次のとおりです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        private CookieContainer cookies;
        public Form1() {
            InitializeComponent();
            backgroundWorker1.DoWork += 
                new DoWorkEventHandler(backgroundWorker1_DoWork);    
        }

        public string od_auth(string s) {    
            if (s.Contains(":")) {
                string[] acc = s.Split(':');
                cookies = new CookieContainer();
                HttpWebResponse res;
                try {
                    HttpWebRequest req = 
                        (HttpWebRequest)HttpWebRequest.Create(
                            "http://m.site.ru/dk?" + 
                            "bk=GuestMain" + 
                            "&st.cmd=main" + 
                            "&tkn=1110" +
                            "&fr.posted=set" +
                            "&fr.needCaptcha=" + 
                            "&fr.login=" + acc[0] + 
                            "&fr.password=" + acc[1] +
                            "&fr.remember=on" + 
                            "&button_login=%D0%92%D0%BE%D0%B9%D1%82%D0%B8"
                        );
                    req.AllowAutoRedirect = false;
                    req.Method = "HEAD";
                    req.CookieContainer = cookies;
                    req.UserAgent = "Opera/9.80 (Windows NT 6.1; U; ru) " +
                                    "Presto/2.2.15 Version/10.10";
                    req.ContentType = "application/x-www-form-urlencoded";
                    res = (HttpWebResponse)req.GetResponse();
                    res.Close();

                    string cook = "";
                    try {
                        if (res.Headers["Location"].Contains("cmd=userMain")) {    
                            cook = "AUTHCODE=" + Regex.Match(res.Headers["Set-Cookie"], @"HCODE=(?<id>[^;]+);").Groups["id"].Value + "; ";
                            cook += "JSESSIONID=" + Regex.Match(res.Headers["Set-Cookie"], @"ESSIONID=(?<id>[^;]+);", RegexOptions.RightToLeft).Groups["id"].Value + ";";
                            richTextBox1.Text += "[+] Авторизовались успешно на " + acc[0] + ":" + acc[1] + "\r\n";
                            return cook;
                        } else {
                            cook = "badacc";
                            richTextBox1.Text += "[-] Аккаунт " + acc[0] + ":" + acc[1] + " невалидный\r\n";
                            return cook;
                        }
                    } catch {
                        cook = "badacc";
                        richTextBox1.Text += "[-] Аккаунт " + acc[0] + ":" + acc[1] + " невалидный\r\n";
                        return cook;
                    }
                }
                catch { richTextBox1.Text += "[?] network error \r\n"; ;return "err"; }
            }

            richTextBox1.Text += "[?] some error \r\n";
            return "err";
        }

        public void od_info_changer(string cook) {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://m.site.ru/dk?bk=UserSettingsProfile&st.cmd=userSettingsProfile&tkn=2154");
            request.Method = "POST";
            request.Headers.Add("Cookie: "+cook);
            request.AllowAutoRedirect = false;
            request.ContentType = "application/x-www-form-urlencoded";
            byte[] EncodedPostParams = Encoding.UTF8.GetBytes("fr.posted=set&fr.name=D1%8F&fr.surname=%D0&fr.gender=1&fr.birthday=12&fr.bmonth=10&fr.byear=1949&fr.country=10414533690&fr.city=%D0%95%D0%BA%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%BD%D0%B1%D1%83%D1%80%D0%B3&button_save=%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B8%D1%82%D1%8C");
            request.ContentLength = EncodedPostParams.Length;
            request.GetRequestStream().Write(EncodedPostParams, 0, EncodedPostParams.Length);
            request.GetRequestStream().Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string html = new StreamReader(response.GetResponseStream(), Encoding.UTF8).ReadToEnd();
            if (response.Headers["Location"].IndexOf("st.cmd=userSettings") != -1) {
                richTextBox1.Text += "[+] Cменили пароль\r\n";
            } else {
                richTextBox1.Text += "[-] Не смогли сменить имя\r\n";
            }               
        }

        List<string> accs=new List<string>();
        private void открытьАккаунтыToolStripMenuItem_Click(object sender, EventArgs e) {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            if (openFileDialog1.ShowDialog() == DialogResult.OK) {
                accs.Clear();
                foreach (string s in File.ReadAllLines(openFileDialog1.FileName))
                    accs.Add(s);

                richTextBox1.Text += "[+] Загрузили " + accs.Count.ToString() + " аккаунтов\n";
            }
        }

        private void Auth_Click(object sender, EventArgs e) {
            Auth.Enabled = false; // На время расчета блокируем опасные кнопки
            backgroundWorker1.RunWorkerAsync();
        }    

        public void go() {
            foreach (string acc in accs) {
                string cook = od_auth(acc);
                if (cook!="badacc")
                    od_info_changer(cook);
            }    
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
            go();
        }
    }
}

ただし、.txtファイルをロードしてボタンを押すと、次のメッセージが表示されます。

このエラーメッセージ

何がうまくいかないのですか?

4

4 に答える 4

3

コントロールをバックグラウンド スレッドから直接更新することはできません。メイン スレッドに戻って呼び出し、そこでアクションを実行する必要があります。

delegate void updateDelegate(string val);

private void UpdateText(string updateVal)
{
    if (richTextBox1.InvokeRequired)
        richTextBox1.Invoke(new updateDelegate(UpdateText), updateVal);
    else
        richTextBox1.Text += updateVal;

}

次に、バックグラウンド ワーカー コードで、 を設定する代わりにrichTextBox1.text、メソッドを呼び出すだけUpdateTextです。

UpdateText("Whatever Value you want");
于 2012-11-30T22:07:40.777 に答える
2

バックグラウンド タスク内で UI コントロールを操作しようとしています。そんなことはできません。実行に時間がかかり、UI と対話しないコード (この場合は HTTP 要求) をDoWorkハンドラーに配置し、結果を表示するコードをRunWorkerCompletedイベント ハンドラーに配置する必要があります。完了イベントは、進行状況変更イベントと同様に、常に UI スレッドで実行されます。

バックグラウンド タスクから定期的に UI を更新する必要がある場合は、通常、進行状況が変更されたことを示します。このような場合、関連する進行状況の変更イベントをサブスクライブし、現在の進行状況をバックグラウンド ワーカーに定期的に渡すことができますReportProgress

UI コントロールで を使用Invokeして、バックグラウンド スレッド内から UI スレッドにマーシャリングできますが、ほとんどの場合、これを避ける必要があります。a を使用する全体的な理由BackgroundWorkerは、それを処理するためです。あなたの仕事は、適切なコードを適切なイベント ハンドラーに配置することだけです。いくつかの特殊なエッジ ケースに使用する必要がInvokeある場合は、その方が簡単な場合もありますが、頻繁に使用している場合は、既存のより高いレベルの抽象化を適切に利用していないことを示しています。

于 2012-11-30T22:13:39.087 に答える
0

Control.Invokeバックグラウンドワーカーからフォームを操作する場合は、を使用する必要があります。ここに説明といくつかの例があります。

于 2012-11-30T22:04:53.787 に答える
0

安全に呼び出す必要があります:

if (richtextBox1.InvokeRequired)
{
 richtextBox1.Invoke(//Delegate);
}
于 2012-11-30T22:08:34.913 に答える