Erweiterte Programmierung


Falls Sie Methoden haben, die eine längere Berechnungszeit erfordern, können Sie diese in einem seperaten Hintergrundthread ausführen lassen. Dolche Hintergrundaufgaben werden in Geschäftsobjekten mit der Klasse gip.core.datamodel.ACBackgroundWorker durchgeführt, die eine Ableitung von System.ComponentModel.BackgroundWorker ist.

Jedes Geschäftsobjekt, besitzt die Eigenschaft "public ACBackgroundWorker BackgroundWorker", die in ACBSO definiert ist. Mit dieser Instanz können Sie eine asynchrone Aufgabe starten, indem Sie die Methode "RunWorkerAsync(object argument)" aufrufen. Als Parameter übergeben Sie den Namen der Methode die asynchron ausgeführt werden soll. Beispiel:

BackgroundWorker.RunWorkerAsync("MyAsyncTask");

Beim Starten der asynchronen Aufgabe wird die virtuelle Methode "BGWorkerDoWork" aufgerufen, weil Sie als Callbackmethode in der ACBSO-Klasse mit dem DoWork-Ereignis des Backgroundworkers verbunden ist.

public virtual void BgWorkerDoWork(object sender, DoWorkEventArgs e)

Überschreiben Sie diese Methode und rufen dort Ihre Methode auf, die in diesem Hintergrundthread ausgeführt werden soll. Beispiel:

public override void BgWorkerDoWork(object sender, DoWorkEventArgs e)
{
base.BgWorkerDoWork(sender, e);
switch (e.Argument.ToString())
{
case "MyAsyncTask":
MyAsyncTask();
break;
}
}

void MyAsyncTask() { ... }

Nachdem Ihre asynchrone Aufgabe ausgeführt wurde, wird die virtuelle Methode "BgWorkerCompleted" aufgerufen, weil Sie als Callbackmethode in der ACBSO-Klasse mit dem RunWorkerCompleted-Ereignis des Backgroundworkers verbunden ist.

public virtual void BgWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

Hier können Sie noch abschliessende Logik einfügen:

public override void BgWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
base.BgWorkerCompleted(sender, e);

ACBackgroundWorker worker = sender as ACBackgroundWorker;
string command = worker.EventArgs.Argument.ToString();
if
(e.Error != null) { ... }

else if (e.Cancelled) { ... }
else {
if (command == "MyAsyncTask") { ... } }

}

 

Sie werden sich fragen, wozu soll ich den BackgroundWorker verwenden, wenn es die Asynchrone Programmierung mit async und wait gibt?

Ja, Sie können dies natürlich auch damit programmieren nur die Anzeige eines Fortschrittes per WPF-Progressbar ist damit nicht möglich. Hierbei unterstützt sie auch das ACBSO.


Um einen Fortschrittsdialog anzuzeigen, rufen Sie "ShowDialog" mit dem Designnamen "Progress" (Konstante DesignNameProgressBar) auf, nachdem Sie "RunWorkerAsync()" aufgerufen haben:

ShowDialog(this, DesignNameProgressBar);

Es erscheint folgender Dialog:

 

Fortschritt initialisieren und ändern

Die Initialisierung des Fortschrittsbalkens und des aktuellen Fortschrittes machen Sie in ihrer Methode, die im Hintergrund ausgeführt werden soll. In dem obigen Beispiel wäre es die Methode MyAsyncTask:

void MyAsyncTask() 
{
CurrentProgressInfo.TotalProgress.ProgressText = "My progress text";
CurrentProgressInfo.TotalProgress.ProgressRangeFrom = 0;
CurrentProgressInfo.TotalProgress.ProgressRangeTo = 1000;
CurrentProgressInfo.TotalProgress.ProgressCurrent = 0;
for (int i = 0; i < 1000; i++)
{
CurrentProgressInfo.TotalProgress.ProgressCurrent++;
// Do some work
}
}

 CurrentProgressInfo ist eine Eigenschaft von ACBSO und vom Typ "gip.core.datamodel.ProgressInfo": 

public class ProgressInfo : INotifyPropertyChanged, IVBProgress
{
public TaskProgressInfo TotalProgress { get; }
public List<TaskProgressInfo> SubTaskList { get; }
}

ProgressInfo wiederum besteht aus "gip.core.datamodel.TaskProgressInfo"-Instanzen. Wobei die Eigenschaft "TotalProgess" den Gesamtfortschritt anzeigt und die Liste "SubTaskList" viele weitere Unterfortschritte anzeigen kann.

public class TaskProgressInfo : INotifyPropertyChanged
{
public int ProgressRangeFrom { get; set; }
public int ProgressRangeTo { get; set; }
public int ProgressCurrent { get; set; }
public string ProgressText { get; set; }
}

Vor Beginn der Aufgaben-Ausführung definieren Sie per ProgressRangeFrom und ProgressRangeTo-Eigenschaft den Bereich des Fortschrittsbalkens. Während der Ausführung inkrementieren Sie die ProgressCurrent-Eigenschaft, damit sich der Fortschrittsbalken im Dialog aktualisiert.

 

Unterfortschritte

Um weitere Fortschrittsbalken für Unteraufgaben anzuzeigen, verwenden Sie die Methode "AddSubTask":

int rangeFrom = 0, rangeTo = 100;
ProgressInfo.AddSubTask("MySubTaskname", rangeFrom, rangeTo);

Um den aktuellen Fortschritt einer Unteraufgabe zu aktualisieren, verwenden Sie die Methode "ReportProgress":

void ReportProgress(string subTaskName, int? progressCurrent, string newProgressText = null)

Im ersten Parameter übergeben Sie den Tasknamen. Übergeben Sie null, wenn Sie den Hauptfortschrittsbalken aktualisieren möchten.
Im zweiten Parameter übergeben Sie den aktuellen Fortschritt. Bei null wird nichts verändert.
Im dritten Parameter übergeben Sie den Fortschritts-Text.  Bei null wird nichts verändert.

// Sets the current progress of a subtask (ProgressCurrent of a instance in SubTaskList):
ProgressInfo.ReportProgress("MySubTaskname", mySubTaskCounter);
// Changes the progresstext of a subtask (ProgressText of a instance in SubTaskList):
ProgressInfo.ReportProgress("MySubTaskname", null, "Completed");
// Changes the total progress (TotalProgress.ProgressCurrent):
ProgressInfo.ReportProgress(null, myMainCounter);
// Changes the progresstext of the main header (TotalProgress.ProgressText):
ProgressInfo.ReportProgress(null, null, "Completed");

ReportProgess löst das Ereignis ProgressCurrent aus das mit der virtuellen Methode
public virtual void BgWorkerProgressChanged(object sender, ProgressChangedEventArgs e) aus ACBSO verbunden ist. Sie können diese Methode überschreiben, falls Sie daran interessiert sind.

 

Individuelles Design

Falls Ihnen das "Progress"-Design  aus ACBSO nicht gefällt, können Sie den Dialog mit einem eigenen Design anzeigen. Entweder Sie machen sich eine Basisklasse für alle Ihrer BSO's bei der Sie das "Progress"-Design überschreiben oder Sie vergeben einen neuen Namen. Das Standarddesign verwendet das iPlus-Steuerelement "gip.core.layoutengine.VBProgressBar" zu Anzeige:

 

Binden Sie die ProgressRangeFrom-Eigenschaft an die "RangeBase.Minimum"-Eigenschaft, ProgressRangeTo and "RangeBase.Maximum" und ProgressCurrent an "RangeBase.Value".