0

I can't get background worker to work. This is my first time using it so I don't know if I have done something wrong. Here's my code:

    int cardcount = 0;
    string lev = "";
    string att = "";
    string atk = "";
    string def = "";
    string ctp = "";
    string id = "";
    void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            string folder = folderBrowserDialog1.SelectedPath;
            DirectoryInfo dinfo = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
            FileInfo[] Files = dinfo.GetFiles("*.jpg");
            int count = Files.Length;
            int current = 0;

            foreach (FileInfo file in Files)
            {
                string path = Path.GetFileNameWithoutExtension(file.Name);
                int cardid = Convert.ToInt32(path);
                if (Program.CardData.ContainsKey(cardid))
                {
                    DevPro_CardManager.cardmaker.IMG = LoadBitmap(folderBrowserDialog1.SelectedPath + "//" + file.Name);
                    id = Program.CardData[cardid].Id.ToString();
                    lev = Program.CardData[cardid].Level.ToString();
                    att = Program.CardData[cardid].Attribute.ToString();
                    if (att == "1")
                    {
                        att = "earth";
                    }
                    else if (att == "2")
                    {
                        att = "water";
                    }
                    else if (att == "4")
                    {
                        att = "fire";
                    }
                    else if (att == "8")
                    {
                        att = "wind";
                    }
                    else if (att == "16")
                    {
                        att = "light";
                    }
                    else if (att == "32")
                    {
                        att = "dark";
                    }
                    else if (att == "64")
                    {
                        att = "divine";
                    }
                    if (Program.CardData[cardid].Atk.ToString() == "-2")
                    {
                        atk = "????";
                    }
                    else
                    {
                        atk = Program.CardData[cardid].Atk.ToString();
                    }
                    if (Program.CardData[cardid].Def.ToString() == "-2")
                    {
                        def = "????";
                    }
                    else
                    {
                        def = Program.CardData[cardid].Def.ToString();
                    }
                    ctp = Program.CardData[cardid].Type.ToString();
                    if (ctp == "2" || ctp == "130" || ctp == "65538" || ctp == "131074" || ctp == "262146" || ctp == "524290")
                    {
                        ctp = "spell";
                    }
                    else if (ctp == "4" || ctp == "1048580" || ctp == "131076")
                    {
                        ctp = "trap";
                    }
                    else if (ctp == "129" || ctp == "161")
                    {
                        ctp = "ritual";
                    }
                    else if (ctp == "65" || ctp == "97")
                    {
                        ctp = "fusion";
                    }
                    else if (ctp == "8193" || ctp == "8225" || ctp == "12321")
                    {
                        ctp = "synchro";
                    }
                    else if (ctp == "8388609" || ctp == "8388641")
                    {
                        ctp = "xyz";
                    }
                    else if (ctp == "33" || ctp == "545" || ctp == "1057" || ctp == "2081" || ctp == "4129" || ctp == "4194337")
                    {
                        ctp = "effect";
                    }
                    else if (ctp == "17" || ctp == "4113")
                    {
                        ctp = "normal";
                    }
                    else if (ctp == "16401")
                    {
                        ctp = "token";
                    }
                    cardcount = cardcount + 1;
                    backgroundWorker1.ReportProgress((current * 100) / count);
                }
            }
        }
    }
    void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // The progress percentage is a property of e
        progressBar1.Value = e.ProgressPercentage;
        label8.Text = cardcount.ToString();
        comboBox2.SelectedItem = lev;
        comboBox1.SelectedItem = att;
        textBox2.Text = atk;
        textBox1.Text = def;
        comboBox3.SelectedItem = ctp;
        GenerateCard();
        ImageResizer.CropImage(361, 523, pictureBox1.Image, @"anime cards\" + Path.GetFileName(id));
    }

And the code for the button that launches it:

 private void button5_Click(object sender, EventArgs e)
    {       
            backgroundWorker1.RunWorkerAsync();
    }

Please help or say if I'm doing something wrong, thanks.

doobop
  • 4,465
  • 2
  • 28
  • 39
outlaw1994
  • 267
  • 6
  • 20
  • What is not working for you ? DoWork is not executed or progres is not notified ? – Kurubaran Aug 31 '13 at 08:07
  • nothing when i click the button nothing happens when it should show an open folder dialog – outlaw1994 Aug 31 '13 at 08:08
  • 2
    The first thing I can tell you is that you definitely shouldn't be trying to show a form inside the `DoWork` method. The `DoWork` method runs on a background thread, not on the UI thread. – Magnus Grindal Bakken Aug 31 '13 at 08:09
  • how would i fix that thanks i gtg for 10 mins so i will reply a bit late – outlaw1994 Aug 31 '13 at 08:10
  • @MagnusGrindalBakken - but the static ShowDialog methods are thread-safe so it will work. Not advisable though. – H H Aug 31 '13 at 08:13
  • well what can i do to make it work – outlaw1994 Aug 31 '13 at 08:25
  • @HenkHolterman I just tested it and I got a ThreadStateException. (Although that only happens if you run it with the debugger attached. Otherwise it just does nothing.) See also this: http://stackoverflow.com/questions/10498555/calling-showdialog-in-backgroundworker – Magnus Grindal Bakken Aug 31 '13 at 08:26
  • @MagnusGrindalBakken - my mistake, this one isn't static and not thead-safe. I was thinking about MessageBox.Show(). – H H Aug 31 '13 at 09:28
  • By the way, I would refactor your code, especially I would replace the if-else if statements with Dictionary att_options (replaces the uneccessary ifs) and then you could say: att = att_options[att]. – Balázs Szántó Aug 31 '13 at 09:50
  • @boli i have no idea how to do that could you please explain a bit more – outlaw1994 Aug 31 '13 at 10:01
  • `string atk = "2"; Dictionary atk_options = new Dictionary() { {"1","earth"}, {"2", "water"}, {"4", "fire"}, }; atk = atk_options[atk];` – Balázs Szántó Sep 01 '13 at 19:18
  • The Dictionary is a hastable/hasmap, you access the elements by a key (not by an index), which could be pretty much any type of object. – Balázs Szántó Sep 01 '13 at 19:21

2 Answers2

1

If you really need to call ShowDialog from the background thread you will need to marshal the call to the foreground thread using Invoke. Here's an example of how you might do this:

public partial class Form1 : Form
{
    private delegate DialogResult ShowFolderBrowser();

    public Form1()
    {
        InitializeComponent();
    }

    private DialogResult ShowFolderBrowserDialog()
    {
        return this.folderBrowserDialog1.ShowDialog();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        if ((DialogResult)this.Invoke(this.ShowFolderBrowserDialog) == DialogResult.OK)
        {
            // ...
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.RunWorkerAsync();
    }
}

However, I would recommend that you rethink your design somewhat. You never explained why you're using a BackgroundWorker in the first place. Why can't you start up the BackgroundWorker after you've shown the folder browser dialog? Like this:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        string folder = e.Argument as string;
        // ...
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (this.folderBrowserDialog1.ShowDialog() == DialogResult.OK)
        {
            string folder = this.folderBrowserDialog1.SelectedPath;
            this.backgroundWorker1.RunWorkerAsync(folder);
        }
    }
}
Magnus Grindal Bakken
  • 2,083
  • 1
  • 16
  • 22
  • the reason im using background worker is for a progress bar as the prog converts a large number of data into pics – outlaw1994 Aug 31 '13 at 09:14
1

The most important detail you overlooked is that you have to do something reasonable when the worker threw an exception. At a minimum, you'll have to report it in your RunWorkerCompleted event handler:

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        if (e.Error != null) {
            MessageBox.Show(e.Error.ToString());
        }
        else {
            // etc..
        }
    }

You will now also discover the problem in your code, you cannot use OpenFileDialog on a worker thread. Display it on the UI thread instead and then start the worker, passing the selection.

And yes, this is different from what you are used to, you expect the debugger to tell you about unhandled exceptions. That doesn't work the same way when a try/catch is wrapping code, they are built into the BackgroundWorker class. You can get the debugger to stop at such an invisible exception with Debug + Exceptions, tick the Thrown checkbox for CLR exceptions. This is not otherwise a good reason to skip the e.Error check in the event handler.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536