/rant
Ik vind dat soort voorbeelden voor delegates best vaak.. Slecht (deze dan iets minder). Of zeggen dat het 'lijkt op een functie-pointer uit C(++)', doh, alsof er dan opeens belletjes gaan rinkelen bij iedereen.
Vooral het voorbeeld waarin een soort calculator gebruikt word. Niet dat het niet klopt, maar omdat geen real-world probleem oplost. Het is leuk, maar veel mensen kunnen het daarna nog steeds niet toepassen en hebben nog geen idee waar ze het over hebben. Het is gewoon geen goede learn by example uitleg, imo.
Een veel betere methode (wederom imo) is probleem vinden in een praktische context.
Zoals: Stel je hebt een object wat een berekening doet. Het zou wenselijk kunnen zijn dat je van dat object informatie terug krijgt met betrekking tot de status van dat object/ die berekening.
Beschouw dit voorbeeld:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| using System;
using System.Windows.Forms;
namespace DelegateExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.Text = "begin";
}
private void run_Click(object sender, EventArgs e)
{
DureOperatie dop = new DureOperatie();
dop.Operatie();
textBox1.Text = "einde";
}
}
}
using System.Threading;
namespace DelegateExample
{
public class DureOperatie
{
public DureOperatie() { }
public void Operatie()
{
for (int i = 1; i < 10; i++)
{
// doe dingen
Thread.Sleep(1000);
}
}
}
} |
Nu gaat het object zijn werk doen, ondertussen blijft je GUI non-responsive en pas als het object klaar is krijg je een melding in het textbox.
Met een delegate kun je zorgen dat er tijdens het lopen van dat object toch communicatie richting
je GUI een ander object is, namelijk als volgt:
Form
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| // run het, druk op start en prober op klik me te drukken
using System;
using System.Windows.Forms;
namespace DelegateExample
{
public partial class Form1 : Form
{
void Update(string up)
{
textBox1.AppendText(up);
}
public Form1()
{
InitializeComponent();
textBox1.Text = "begin";
}
private void run_Click(object sender, EventArgs e)
{
DureOperatie dop = new DureOperatie();
dop.Operatie(Update);
textBox1.AppendText("Einde");
}
private void stoprun_Click(object sender, EventArgs e)
{
MessageBox.Show("heeeeeeeee");
}
}
} |
DureOperatie.cs
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| using System.Threading;
namespace DelegateExample
{
public class DureOperatie
{
public delegate void Updater(string update);
public DureOperatie() { }
public void Operatie(Updater updater)
{
for (int i = 1; i < 10; i++)
{
// doe dingen
Thread.Sleep(1000);
if(updater!=null)
updater(string.Format("Bezig met: {0}", i));
}
}
}
} |
Nu zorgt de delegate ervoor dat je UI ge-update wordt.
Uiteraard kun je hier verder in gaan, door het gebruik van thread/backgroundworker kun je er voor zorgen dat je UI als geheel responsive blijft. Zodat je tijdens het uitvoeren van de dure operatie de knop klik me kan gebruiken. Dat wordt dan zoiets:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace DelegateExample
{
public partial class Form1 : Form
{
public BackgroundWorker bgWorker;
void Update(string up)
{
Invoke((Action)delegate { textBox1.AppendText(up); });
}
public Form1()
{
InitializeComponent();
textBox1.Text = "begin";
}
private void run_Click(object sender, EventArgs e)
{
bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
bgWorker.RunWorkerAsync();
}
void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
textBox1.AppendText("KLAAR");
}
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
DureOperatie dop = new DureOperatie();
dop.Operatie(Update);
}
private void klikme_Click(object sender, EventArgs e)
{
MessageBox.Show("heeeeeeeee");
}
}
} |
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| using System.Threading;
namespace DelegateExample
{
public class DureOperatie
{
public delegate void Updater(string update);
public DureOperatie() { }
public void Operatie(Updater updater)
{
for (int i = 1; i < 10; i++)
{
// doe dingen
Thread.Sleep(1000);
if(updater!=null)
updater(string.Format("Bezig met: {0}", i));
}
}
}
} |
Voor het gemak nog even de designer code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
| namespace DelegateExample
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.run = new System.Windows.Forms.Button();
this.klikme = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(9, 4);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(38, 13);
this.label1.TabIndex = 0;
this.label1.Text = "status:";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 20);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(260, 84);
this.textBox1.TabIndex = 1;
//
// run
//
this.run.Location = new System.Drawing.Point(116, 110);
this.run.Name = "run";
this.run.Size = new System.Drawing.Size(75, 23);
this.run.TabIndex = 2;
this.run.Text = "start";
this.run.UseVisualStyleBackColor = true;
this.run.Click += new System.EventHandler(this.run_Click);
//
// klikme
//
this.klikme.Location = new System.Drawing.Point(197, 110);
this.klikme.Name = "klikme";
this.klikme.Size = new System.Drawing.Size(75, 23);
this.klikme.TabIndex = 3;
this.klikme.Text = "klik me";
this.klikme.UseVisualStyleBackColor = true;
this.klikme.Click += new System.EventHandler(this.klikme_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 134);
this.Controls.Add(this.klikme);
this.Controls.Add(this.run);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button run;
private System.Windows.Forms.Button klikme;
}
} |
Volgens mij heb je nu een best duidelijk voorbeeld van hoe je interactie tussen 2 objecten kunt bewerkstelligen en nog een extraatje voor je UI.
Het is slechts een voorbeeld en er zijn meerdere wegen die naar rome leiden (of lijden

), maar her illustreert wel de functionaliteit op een duidelijke manier, IMO.
Eeeeeh, tijd teveel.