0

So i have form1 which has backgroundworker (dragged and dropped via design view). I can get it to work in the places i need, however I need to call it from a public method.

In this public method

Utility.initpacks(object sender, EventArgs e,string formname)

SO my DoWork is in Form1.

I the public utility within the form do do a bunch of things, then THAT function needs to use the background worker inside Form1 again!

I could just copy the public method and put in the place of the method reference and all is well.. but that defeats the purpose of a public method doesn't it!?

Any ideas would be great thanks :)

EDIT:

SO my current setup (without a bunch of stuff not important):

public partial class frmimportinstitutions : Form
    {
    private void btnNext_Click(object sender, EventArgs e)
         {
         Utility.initpacks(sender, e, this.FindForm().Name);
         }




    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //Do stuff

        }
}

public static class Utility
    {
public static void initpacks(object sender, EventArgs e,string formname)
        {
//I WANT TO USE THE BACKGROUND WORKER HERE
//Do a public method
//I want to stop the background worker here
}
}

Update (basd on comments):

Michael comments just mentioned to put the background worker starting in a public method:

public void startplash(string starttext)
        {
            if (!backgroundWorker1.IsBusy)
            {
                splashtext = starttext;
                backgroundWorker1.RunWorkerAsync();
            }

        }

Now i want to call this method from the other method. In order to do this, the other method (init packs) needs to know where this method is doesnt it. EG.

form1.startsplash("hello world")

So now i just need to send Form1 info to init packs...

Would this be ok:

Initpacks(Form Owner)
{
Owner.startsplash("hello world")
}

Another update! Thanks for Michael we so far have this:

public static class Utility
{
    public static void RunWorkerOfForm1()
    {
        var target = (Form1)Application.OpenForms.OfType<Form1>().FirstOrDefault();
        target?.RunWorker();
    }
}

Now I need to get this to work with different forms.. I havent tried the below but this is what i am going to try next.. correct me if i am wrong:

public static class Utility
{
    public static void RunWorkerOfForm1(Form owner)
    {
        var target = (owner)Application.OpenForms.OfType<owner>().FirstOrDefault();
        target?.RunWorker();
    }
}

Final Answer (as per the ticked answer) - but using my code:

public partial class frmholidaypacks : Form, IWorker
    {
private void btnextrapacks_Click(object sender, EventArgs e)
        {
         Utility.futurepacks<frmholidaypacks>(sender, e, pxid);
         }
     }

public interface IWorker
    {
        void startplash(string starttext);

    }

public void startplash(string starttext)
        {
            if (!backgroundWorker1.IsBusy)
            {
                splashtext = starttext;
                backgroundWorker1.RunWorkerAsync();
            }

        }

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //Doing work.  Using Splashtext string.

        }

public static void futurepacks<T>(object sender, EventArgs e, int pxid) where T : IWorker
        {
 var target = (T)Application.OpenForms.OfType<T>().FirstOrDefault();
            target?.startplash("Creating future packs");
        }

100% Credit goes to Michael for working on this with me!

Glenn Angel
  • 381
  • 1
  • 3
  • 14
  • Can i just in the arguments for the method use (Backgroundworker BGW)..? Would BGW.runasync() run the dowork part of that background worker on the other form? – Glenn Angel Oct 18 '17 at 14:53
  • I dont really understand what you want to do, but if you want to start the `BackgroundWorker` from an external method thats not part of the `Form` there are not that many ways to do it: 1) make the `BackgroundWorker` a public member of that form (bad) 2) add a public method to the form that runs `backgroundWorker.RunAsync` - be sure to check the `Busy` state of the `BackgroundWorker`. Both variants can/should be abstracted with some interface. – Michael Oct 18 '17 at 14:55
  • ok thanks Michael, i was just working on the second option. I have the backgroundworker.runasync inside a public method now in that form, but how do i pass that to the other public method, eg. Send form object as owner to the method as an arguament? – Glenn Angel Oct 18 '17 at 14:58
  • Third method: Define a (job) queue in the main form. Define a public method for adding jobs. Run an endless loop inside your `BackgroundWorker` that checks the queue on each iteration, sleeping some time if no job present and extracting and processing a job if there is something to process. add `null` or a specific object and check for that object in the `BackgroundWorker` if you want to quit processing... Might be a bit to much for your case... – Michael Oct 18 '17 at 15:01
  • updated my question with an update of your option2 method michael, thanks for the help – Glenn Angel Oct 18 '17 at 15:06
  • Just provide the `BackgroundWorker` reference to that method as an argument, – dymanoid Oct 18 '17 at 15:06
  • thanks Dymanoid. The public method is working, i just need to make it work for different forms that call it. Calling the BGW alone isnt good, as i have realised there are other 'things' i need to bulk together on that form prior to calling the bgw so the method fixed a few issues in one. – Glenn Angel Oct 18 '17 at 15:09

2 Answers2

0

EDITED!

Ok, now I got it. Every form you want to run have to implement the IWorker interface. Then you pass the concrete Form to use as a generic parameter to the RunWorker function. The where clause only allows implementations of the IWorker interface - its (currently) not restricted to Form-instances.

public partial class Form2 : Form, IWorker
{
    public Form2()
    {
        InitializeComponent();
    }

    public void RunWorker()
    {
        if (backgroundWorker1.IsBusy) return;
        backgroundWorker1.RunWorkerAsync();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        UtilityX.RunWorker<Form2>();
    }
}

public static class UtilityX
{
    public static void RunWorker<T>() where T : IWorker
    {
        var target = (T)Application.OpenForms.OfType<T>().FirstOrDefault();
        target?.RunWorker();
    }
}

public interface IWorker
{
    void RunWorker();
}
Michael
  • 1,931
  • 2
  • 8
  • 22
  • Thanks Michael, almost there. I got what you wrote prior to you putting it there and my final issue is what if form2 and form1 both need access now to this RunWorkerOfForm1. eg. RunworkerofFORM. Because the point of this is i have a worker on 3 different forms and each needs to run depending on which form has called initpacks method – Glenn Angel Oct 18 '17 at 15:11
  • @GlennAngel What you want should be possible with the above code. What should happen if another form calls `RunWorkerOfForm1` and the background worker is already running? Should the current process be canceled, should it wait until the current run finishes or ...? – Michael Oct 18 '17 at 15:23
  • BUt shouldnt this (Form1)Application.OpenForms.OfType().FirstOrDefault(); be (Form2)Application.OpenForms.OfType().FirstOrDefault(); – Glenn Angel Oct 18 '17 at 15:33
  • 1
    In my sample the BackgroundWorker is part of Form1... In your case it should be `Application.OpenForms.OfType().FirstOrDefault()` – Michael Oct 18 '17 at 15:40
  • i updated my question at the bottom with what i want, but i know my answer is wrong so far. Form cant be used! – Glenn Angel Oct 18 '17 at 15:49
  • @GlennAngel Updated/Changed my example. This should work with every form that implements the `IWorker` interface. – Michael Oct 18 '17 at 15:59
  • Great. so i just create another interface and do the same thing to do cancelasync? – Glenn Angel Oct 18 '17 at 16:03
  • i have the iworker outside of the form2 like you have got there, but when i use the UtilityX.RunWorker(); I ma getting "There is no implicit reference conversion to Namespace.IWorker" – Glenn Angel Oct 18 '17 at 16:08
  • Does `Form2` implements `IWorker`? – Michael Oct 18 '17 at 16:17
  • i have got the same code in form1 and form2, the iworker code is on form2 page but outside the form2 brackets – Glenn Angel Oct 18 '17 at 16:22
  • 1
    Thats not really what i meant. You should read a little bit about what interfaces are and how to implement them. Basically an interface defines *public* methods and/or properties. Classes that 'want' to implement an interface must define exactly the same methods and properties as the interface. To implement an interface you put the interface name in the same line as the class definition, like this: `public class MyForm: Form, IWorker`. This forces the class MyForm to provide the methods that are defined in the interface. – Michael Oct 18 '17 at 16:34
  • oh damn didnt see that, sorry – Glenn Angel Oct 18 '17 at 16:35
  • amzing. IT WORKSSSSS THANKS so much. Im going to read up on interface now. never used it before so want to know what I'm doing here :) Thanks again mate, really happy with that – Glenn Angel Oct 18 '17 at 16:41
-1

Have you tried to use a static method, you can put your code in a static method if you want too use it from multiple places.

public class MyClass
    {
        public static void MyMethod()
        {
           //..
        }
    }
Ehsan Zargar Ershadi
  • 24,115
  • 17
  • 65
  • 95
  • I think using EventArgs is probably a better solution. – Aaron Oct 18 '17 at 14:44
  • Hi Ehsan, thanks for the reply. What would i put in there?? The do work function? utility.init packs IS a public static method, but inside that i need to call backgroundworker.RunAsync() – Glenn Angel Oct 18 '17 at 14:45
  • You need to place the part of data which is used in the logic of background data, so you could change or read the data in the background DoWork method – Ehsan Zargar Ershadi Oct 18 '17 at 14:54