Avatar billede sandrasmurf Nybegynder
29. februar 2008 - 21:38 Der er 7 kommentarer og
1 løsning

BackGroundWorker og progressbar

Hej eksperter

Der skal en progressbar ind i mit program og jeg har bestemt mig for at bruge en BackgroundWorker control + en progressbar control.

Alle eksempler i google "snyder" ved at udføre iterationerne i backgroundworkerens DoWork del. Så er det ret nemt at opdatere sin progressbar.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = (BackgroundWorker)sender;
    System.Random rand = new Random();
    int max = rand.Next(50, 500);
    for (int i = 0; i < max; i++)
    {
      // Sleep for 30 milliseconds
      System.Threading.Thread.Sleep(30);
      worker.ReportProgress((int)i * 100 / max);
    }
    // Pass up the number of iterations perform to the main thread
    e.Result = max;
}

Hvad hvis man kalder en metode i en anden klasse. Hvad er den bedst måde at få rapporteret progress tilbage fra et metode kald, når man bruger BackGroundWorkeren? Og hvad hvis man som jeg bruger en Mediator klasse som mellemled.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  MyClass mc = new MyClass();
  mc.DoWork();

  // ? report progress.
}
Avatar billede dr_chaos Nybegynder
29. februar 2008 - 21:41 #1
så skal du lave din DoWork methode på denne måde i MyClass:

DoWork(BackgroundWorker bw)
{
//lavnoget

bw.ReportProgress((int)i * 100 / max);
}
Avatar billede sandrasmurf Nybegynder
01. marts 2008 - 20:39 #2
Det er naturligvis en løsning. Havde jeg faktisk slet ikke tænkt på :-)

Men når man forsøger at opbygge sin program med en mediator, der er koblingen mellem GUI og Logik, så bryder det med Model-View-Control designet at sende en Control ind i en Model/Logik klasse. Idéen er jo netop at lave en skarp opdeling mellem model og GUI.

Lader spørgsmålet stå åben lidt endnu for at høre om andre har et andet forslag.
Avatar billede dr_chaos Nybegynder
01. marts 2008 - 20:49 #3
Ja.
Så lav et event i MyClass som du kan abonnerer på i din gui.
Når det event bliver firet kan du så kalde ReportProgress i din gui.
På den måde bryder du ikke dit pattern.
Avatar billede sandrasmurf Nybegynder
01. marts 2008 - 22:08 #4
Så har jeg smidt følgende i min tidskrævende metode i logikken:

public delegate void ProgressChanged(int progressPercentage);
public event ProgressChanged SimulationProgressChanged;
protected virtual void OnSimulationProgress(int percentage)
{
    if(SimulationProgressChanged != null)
        SimulationProgressChanged(percentage);
}

Så kan jeg i GUI'en med min Worker og progressbar skrive:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    MySimulation sim = new Simulation();
    sim.SimulationProgressChanged += new MySimulation.ProgressChanged(sim_SimulationProgressChanged);
}

void sim_SimulationProgressChanged(int progressPercentage)
{           
      backgroundWorker1.ReportProgress(progressPercentage);
}

Har du/nogen et bud på hvordan man får understøttet en cancel knap.

private void cancelGlassButton_Click(object sender, EventArgs e)
{
  // Cancel asynchronous processing
  if (backgroundWorker1.IsBusy)
      backgroundWorker1.CancelAsync();           
}
Avatar billede dr_chaos Nybegynder
01. marts 2008 - 22:37 #5
Hvis du cancellerer din tråd bør arbejdet i my class også stoppe automatisk.
Avatar billede dr_chaos Nybegynder
01. marts 2008 - 22:48 #6
Jeg har selv brugt denne implementering af backgroundworker for at få en ordentlig cancellering:
ow///Created by Roy Osherove, Team Agile
/// Blog: www.ISerializable.com
/// Roy@TeamAgile.com
namespace WindowsApplication2
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Security.Permissions;
    using System.Threading;
    using System.ComponentModel;

/// <summary>
/// Replaces the standard BackgroundWorker Component in .NET 2.0 Winforms
/// To support the ability of aborting the thread the worker is using,
///and supporting the fast proporgation of ProgressChanged events without locking up
/// </summary>
/// <remarks></remarks>
    public class BackgroundWorkerEx : Component
    {
        // Events
        public event DoWorkEventHandler DoWork
        {
            add
            {
                base.Events.AddHandler(BackgroundWorkerEx.doWorkKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(BackgroundWorkerEx.doWorkKey, value);
            }
        }
        public event ProgressChangedEventHandler ProgressChanged
        {
            add
            {
                base.Events.AddHandler(BackgroundWorkerEx.progressChangedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(BackgroundWorkerEx.progressChangedKey, value);
            }
        }
        public event RunWorkerCompletedEventHandler RunWorkerCompleted
        {
            add
            {
                base.Events.AddHandler(BackgroundWorkerEx.runWorkerCompletedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(BackgroundWorkerEx.runWorkerCompletedKey, value);
            }
        }

        // Methods
        static BackgroundWorkerEx()
        {
            BackgroundWorkerEx.doWorkKey = new object();
            BackgroundWorkerEx.runWorkerCompletedKey = new object();
            BackgroundWorkerEx.progressChangedKey = new object();
        }

        public BackgroundWorkerEx()
        {
            this.threadStart = new WorkerThreadStartDelegate(this.WorkerThreadStart);
            this.operationCompleted = new SendOrPostCallback(this.AsyncOperationCompleted);
            this.progressReporter = new SendOrPostCallback(this.ProgressReporter);
        }

        private void AsyncOperationCompleted(object arg)
        {
            this.isRunning = false;
            this.cancellationPending = false;
            this.OnRunWorkerCompleted((RunWorkerCompletedEventArgs)arg);
        }

        public void CancelAsync()
        {
            if (!this.WorkerSupportsCancellation)
            {
                throw new InvalidOperationException("BackgroundWorker_WorkerDoesntSupportCancellation");
            }
            this.cancellationPending = true;
        }

        protected virtual void OnDoWork(DoWorkEventArgs e)
        {
            mThread = Thread.CurrentThread;
            DoWorkEventHandler workStartDelegate = (DoWorkEventHandler)base.Events[BackgroundWorkerEx.doWorkKey];
            if (workStartDelegate != null)
            {
                try
                {
                    workStartDelegate(this, e);
                }
                catch (ThreadAbortException)
                {
                    Thread.ResetAbort();
                }
            }
        }

        private object tempLock = new object();
        protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
        {
            ProgressChangedEventHandler progressChangedDelegate = (ProgressChangedEventHandler)base.Events[BackgroundWorkerEx.progressChangedKey];
            if (progressChangedDelegate != null)
            {
                progressChangedDelegate(this, e);
            }
        }

        protected virtual void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
        {
            RunWorkerCompletedEventHandler workderCompletedDelegate = (RunWorkerCompletedEventHandler)base.Events[BackgroundWorkerEx.runWorkerCompletedKey];
            if (workderCompletedDelegate != null)
            {
                workderCompletedDelegate(this, e);
            }
        }

        private void ProgressReporter(object arg)
        {
            this.OnProgressChanged((ProgressChangedEventArgs)arg);
        }

        public void ReportProgress(int percentProgress)
        {
            this.ReportProgress(percentProgress, null);
        }

        public void ReportProgress(int percentProgress, object userState)
        {
            if (!this.WorkerReportsProgress)
            {
                throw new InvalidOperationException("BackgroundWorker_WorkerDoesntReportProgress");
            }
            ProgressChangedEventArgs progressArgs = new ProgressChangedEventArgs(percentProgress, userState);
            object lockTarget = new object();
            if (this.asyncOperation != null)
            {
                this.asyncOperation.Post(this.progressReporter, progressArgs);
              // Thread.Sleep(10);
            }
            else
            {
                this.progressReporter(progressArgs);
            }
        }

        public void RunWorkerAsync()
        {
            this.RunWorkerAsync(null);
        }

        private Thread mThread;
        public void StopImmediately()
        {
            if (!IsBusy || mThread == null)
            {
                return;
            }
            else
            {
                mThread.Abort();
                //there is no need to catch a threadAbortException
                //since we are catching it and resetting it inside the OnDoWork method
            }
           

            RunWorkerCompletedEventArgs completedArgs =
                new RunWorkerCompletedEventArgs(null, null, true);
            if (asyncOperation != null)
            {
                //invoke operation on the correct thread
                asyncOperation.PostOperationCompleted(operationCompleted, completedArgs);
            }
            else
            {
                //invoke operation directly
                operationCompleted(completedArgs);
            }
        }

        public void RunWorkerAsync(object argument)
        {
            if (this.isRunning)
            {
                throw new InvalidOperationException("BackgroundWorker_WorkerAlreadyRunning");
            }
            this.isRunning = true;
            this.cancellationPending = false;
            this.asyncOperation = AsyncOperationManager.CreateOperation(null);
            this.threadStart.BeginInvoke(argument, null, null);
        }

        private void WorkerThreadStart(object userState)
        {
            object result = null;
            Exception workerException = null;
            bool cancel = false;
            try
            {
                DoWorkEventArgs workArgs = new DoWorkEventArgs(userState);
                this.OnDoWork(workArgs);
                if (workArgs.Cancel)
                {
                    cancel = true;
                }
                else
                {
                    result = workArgs.Result;
                }
            }
            catch (Exception ex)
            {
                workerException = ex;
            }
            RunWorkerCompletedEventArgs completedArgs = new RunWorkerCompletedEventArgs(result, workerException, cancel);
            if (isRunning)
            {
                this.asyncOperation.PostOperationCompleted(this.operationCompleted, completedArgs);
            }
        }


        // Properties
        public bool CancellationPending
        {
            get
            {
                return this.cancellationPending;
            }
        }

        public bool IsBusy
        {
            get
            {
                return this.isRunning;
            }
        }

        public bool WorkerReportsProgress
        {
            get
            {
                return this.workerReportsProgress;
            }
            set
            {
                this.workerReportsProgress = value;
            }
        }

        public bool WorkerSupportsCancellation
        {
            get
            {
                return this.canCancelWorker;
            }
            set
            {
                this.canCancelWorker = value;
            }
        }


        // Fields
        private AsyncOperation asyncOperation;
        private bool canCancelWorker;
        private bool cancellationPending;
        private static readonly object doWorkKey;
        private bool isRunning;
        private readonly SendOrPostCallback operationCompleted;
        private static readonly object progressChangedKey;
        private readonly SendOrPostCallback progressReporter;
        private static readonly object runWorkerCompletedKey;
        private readonly WorkerThreadStartDelegate threadStart;
        private bool workerReportsProgress;

        // Nested Types
        private delegate void WorkerThreadStartDelegate(object argument);

    }
}
Avatar billede sandrasmurf Nybegynder
02. marts 2008 - 19:14 #7
Jeg siger tak for hjælpen og kigger nærmere på dit eksempel :-)
Avatar billede dr_chaos Nybegynder
02. marts 2008 - 21:09 #8
np :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester