¿BackgroundWorker informa el progreso de la clase externa?

Tengo una solución funcional que informa el progreso y el texto en una barra de progreso y una etiqueta en el formulario principal de las aplicaciones. Ahora he movido mis métodos de trabajo a una clase para que sean accesibles a través de múltiples formularios, etc.

Dentro de los métodos de trabajo están BW.ReportProgress() declaraciones que retroceden el progreso y el texto al BackgroundWorker en el formulario principal.

Para dar una mejor idea aquí está el diseño del archivo:

MainScreen.cs

List repSelected = new List();
XMLandRar xXMLandRar = new XMLandRar();

private void Rarbtn_Click(object sender, EventArgs e)
        {
            GetReps();

            //Run worker
            if (!CreateRarBW.IsBusy)
            {
                CreateRarBW.RunWorkerAsync();
            }
        }

//Worker
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    xXMLandRar.RarFiles(repSelected);
}

//Progress reporting
private void CreateRarBW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progBar.Value = e.ProgressPercentage;
    Statuslbl.Text = e.UserState.ToString();
}

Luego, mi Clase recién creada que abarca todos los métodos de trabajo y es impulsar el progreso al formulario principal.

XMLandRar.cs

public class XMLandRar
{
    public void RarFiles(List repSelected)
    {
        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            CreateRarBW.ReportProgress(i, "Raring files for " + rep);
            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;
            CreateRarBW.ReportProgress(i, "Raring files for " + rep);
        }
    }
}

El problema que tengo es que en el XMLandRar class the CreateRarBW no se reconoce (obviamente) - ¿cómo puedo hacer un ReportProgress llamar al BW en la pantalla principal de la aplicación?

preguntado el 22 de mayo de 12 a las 11:05

3 Respuestas

Crea un evento en tu XMLandRar clase a la que podrías suscribirte.

De esta manera el XMLandRar class no necesita saber o preocuparse por la interfaz de usuario o la barra de progreso, solo se preocupa por enviar un mensaje si alguien lo escucha. Y también puede haber más de un suscriptor (digamos si desea informar al trabajador en segundo plano y un registro, tal vez)

Ejemplo:

private void Rarbtn_Click(object sender, EventArgs e)
{
    GetReps();

    //Run worker
    if (!CreateRarBW.IsBusy)
    {
        // This should be done once, maybe in the contructor. Bind to new event.
        xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);

        CreateRarBW.RunWorkerAsync();
    }
}

protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
{
    // Call the UI backgroundworker
    CreateRarBW.ReportProgress(e.Percentage, e.Message);
}

public class XMLandRar
{
    // Event handler to bind to for reporting progress
    public EventHandler<ProgressArgs> ReportProgress;

    // Eventargs to contain information to send to the subscriber
    public class ProgressArgs : EventArgs
    {
        public int Percentage { get; set; }
        public string Message { get; set; }
    }

    public void RarFiles(List repSelected)
    {
        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            // Report progress if somebody is listening (subscribed)
            if (ReportProgress != null)
            {
                ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
            }

            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;

            // Report progress if somebody is listening (subscribed)
            if (ReportProgress != null)
            {
                ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
            }
        }
    }
}

contestado el 22 de mayo de 12 a las 12:05

Exactamente lo que buscaba, +1! - Myles Grey

Por supuesto, esto podría optimizarse un poco y extenderse, pero entiendes la idea básica. =) - Mario S.

La sender objeto en el DoWork devolución de llamada es el BackgroundWorker instancia que está llamando a esta devolución de llamada.

Esto permite usar la instancia y agregarla a su nuevo XMLandRar clase.

private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker.
    xXMLandRar.RarFiles(repSelected, worker);
}

XMLandRar.cs

public class XMLandRar
{
    public void RarFiles(List repSelected, BackgroundWorker worker)
    {
    // ...
    }
}


Or tu pones el BackgroundWorkerinstancia como una propiedad de clase a la XMLandRar.

public class XMLandRar
{
    protected BackgroundWorker mWorker;

    public XMLandRar(BackgroundWorker worker) {
        mWorker = BackgroundWorker;
    }


    public void RarFiles(List repSelected)
    {
        // Do something with {mWorker}
    }
}

Or como se menciona en los comentarios, usando eventos en el XMLandRar clase.

XMLandRar.cs

public class XmlandRarCompletedEventArgs : EventArgs
{
    public readonly bool Finished;
    public readonly bool Canceled;

    public XmlandRarCompletedEventArgs(bool finished)
    {
        Finished = finished;
        Canceled = !finished;
    }    

}public class OnXmlandRarUpdateEventArgs : EventArgs
{
    public readonly int Percentage;
    public readonly string Message;

    public XmlandRarCompletedEventArgs(int perc) :
        this(perc, "") {
    }   

    public XmlandRarCompletedEventArgs(int perc, string message)
    {
        Percentage = perc;
        Message = message;
    }    

}

public delegate void OnXmlandRarDoWorkHandler(object o);
public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);

public class XMLandRar
{
    public event OnXmlandRarDoWorkHandler OnDoWork;
    public event OnXmlandRarUpdateHandler OnUpdate;
    public event OnXmlandRarCompletedHandler OnComplete;

    public void RarFiles(List repSelected)
    {
        TriggerDoWork();

        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            TriggerUpdate(i, "Raring files for " + rep);
            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;
            TriggerUpdate(i, "Raring files for " + rep);
        }

        TriggerComplete(true);
    }


    private void TriggerDoWork() 
    {
        if (OnDoWork != null) {
            OnDoWork(this);
        }
    }

    private void TriggerUpdate(perc) {
    }
        if (OnUpdate != null) {
            OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
        }

    private void TriggerUpdate(perc, string message) 
    {
        if (OnUpdate != null) {
            OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
        }
    }

    private void TriggerComplete(bool finished)
    {
        if (OnComplete != null) {
            OnComplete(this, new XmlandRarCompletedEventArgs(finished));
        }
    }
}

Uso:

private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;
    // Attach events to class
    xXMLandRar.OnDoWork += delegate(object o) {
        // ...
    };
    xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args) {
        // ...
    };
    xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args) {
        // ...
    };
    xXMLandRar.RarFiles(repSelected, worker);
}

Con suerte sin errores tipográficos porque estoy en la oficina.

contestado el 22 de mayo de 12 a las 12:05

@HenkHolterman - ¿Puede elaborar una respuesta, por favor? ¿Quiere decir que para ser una clase reutilizable adecuada, RarFiles no debe conocer la GUI, ya que eso lo haría específico para esa situación? - Myles Grey

@HenkHolterman Entonces, lo que realmente necesito hacer es separar el código de modificación de la GUI, colocarlo en el formulario principal y tener solo un evento de actualización de informe genérico/devolución de llamada en la clase que cualquier formulario/CLI/página puede escuchar y procesar en su ¿Propia manera? - Myles Grey

Gracias @GodLesZ - Buena solución, estoy seguro de que usaré partes para completar, etc. +1. - Myles Grey

He corregido errores en el código enviado y lo he limpiado... Esta es una muestra de trabajo que ayudará a aquellos que tal vez no pudieron entender el código ya que estaba roto como estaba... Aunque me gustaría decir que el la intención y la funcionalidad del código después de limpiarlo y mejorarlo son excelentes.

Este es un código de trabajo que puede ayudarlo a comenzar su proyecto para usar un subproceso backGroundWorker para lo que necesite.

Simplemente modifique este método -

    public void RarFiles(List<string> repSelected)

Para hacer cualquier trabajo que necesites. También tendrá que modificar los argumentos que planea usar... es decir, es posible que necesite un DataTable o algún objeto personalizado... Puede modificar el

     public class OnXmlandRarUpdateEventArgs : EventArgs

Para sus necesidades... de esa manera, cuando reciba una devolución de llamada... puede actualizar su formulario de interfaz de usuario principal con los cambios realizados en esos elementos...

Es posible que tengas que hacer algunos ajustes... pero ya ves a lo que me refiero...

Este es el código del formulario... No olvides crear un botón en el formulario...

    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;

    namespace ThreadSample
    {
        public partial class Form1 : Form
        {
            List<string> repSelected = new List<string>();
            XMLandRar xXMLandRar = new XMLandRar();
            BackgroundWorker CreateRarBW = new BackgroundWorker();
            public Form1()
            {
                InitializeComponent();
                repSelected = new List<string> { "asdf", "asdfsd", "h;ljj" };
                CreateRarBW.DoWork += new DoWorkEventHandler(CreateRarBW_DoWork);
            }

            private void Rarbtn_Click(object sender, EventArgs e)
            {
                //GetReps();

                //Run worker
                if (!CreateRarBW.IsBusy)
                {
                    // This should be done once, maybe in the contructor. Bind to new event.
                    xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);

                    CreateRarBW.RunWorkerAsync();
                }
            }

            protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
            {
                // Call the UI backgroundworker
                CreateRarBW.ReportProgress(e.Percentage, e.Message);
            }

            //private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
            //{
            //    var worker = sender as BackgroundWorker;
            //    xXMLandRar.RarFiles(repSelected, worker);
            //}


            private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
            {
                var worker = sender as BackgroundWorker;
                // Attach events to class
                xXMLandRar.OnDoWork += delegate(object o)
                {
                    // ...
                    MessageBox.Show("Hey ... Something is going on over there in the classLib .. " + o);
                };
                xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args)
                {
                    // ...
                    //foreach (object oo in args)
                    {
                        MessageBox.Show("Hey ... Something is going on over there in the classLib .. Message is " + args.Message + " and Percentage is " + args.Percentage);
                    }
                };
                xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args)
                {
                    MessageBox.Show("Hey ... Something is going on over there in the classLib .. Canceled is " + args.Canceled + " and Finished is " + args.Finished);
                    // ...
                };
                xXMLandRar.RarFiles(repSelected);//, worker);
            }
        }
    }

Este es el código de la clase. Simplemente puede crear una clase en su proyecto actual... Tenga en cuenta que el objeto CreateRarBW es una instancia de BackGroundWorker... (No se incluyó arriba...)

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Diagnostics;
    using System.Threading;

    namespace ThreadSample
    {
        public class XmlandRarCompletedEventArgs : EventArgs
        {
            public readonly bool Finished;
            public readonly bool Canceled;

            public XmlandRarCompletedEventArgs(bool finished)
            {
                Finished = finished;
                Canceled = !finished;
            }
        }

        public class OnXmlandRarUpdateEventArgs : EventArgs
        {
            public readonly int Percentage;
            public readonly string Message;


            public OnXmlandRarUpdateEventArgs(int perc) : this(perc, "")
            {

            }   

            public OnXmlandRarUpdateEventArgs(int perc, string message)
            {
                Percentage = perc;
                Message = message;
            }

        }

        public delegate void OnXmlandRarDoWorkHandler(object o);
        public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
        public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);

        public class XMLandRar      // : BackgroundWorker
        {

            // Event handler to bind to for reporting progress
            public EventHandler<ProgressArgs> ReportProgress;

            // Eventargs to contain information to send to the subscriber
            public class ProgressArgs : EventArgs
            {
                public int Percentage { get; set; }
                public string Message { get; set; }
            }

            public event OnXmlandRarDoWorkHandler OnDoWork;
            public event OnXmlandRarUpdateHandler OnUpdate;
            public event OnXmlandRarCompleteHandler OnComplete;

            public void RarFiles(List<string> repSelected)
            {
                TriggerDoWork();

                int step = 100 / repSelected.Count();
                int i = 0;
                //Iterate through list and run rar for each
                foreach (string rep in repSelected)
                {
                    TriggerUpdate(i, "Raring files for " + rep);
                    //DirectoryExists(rep);
                    //ProcessRunner(rep);
                    i += step;
                    TriggerUpdate(i, "Raring files for " + rep);
                }

                TriggerComplete(true);
            }


            private void TriggerDoWork()
            {
                if (OnDoWork != null)
                {
                    OnDoWork(this);
                }
            }

            private void TriggerUpdate(int perc)
            {

                if (OnUpdate != null)
                {
                    OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
                }
            }

            private void TriggerUpdate(int perc, string message)
            {
                if (OnUpdate != null)
                {
                    OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
                }
            }

            private void TriggerComplete(bool finished)
            {
                if (OnComplete != null)
                {
                    OnComplete(this, new XmlandRarCompletedEventArgs(finished));
                }
            }
        }

    }

respondido 07 nov., 15:23

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.