原来一直以为silverlight里的事件机制也和wpf中的一样或和flex中的一样。但好像并非如此。而是采用了传统的delegate,并不是flex中的事件机制:
以下代码是一个PieChart控件, 当中的事件就是采用delegate

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Windows;
5
using System.Windows.Controls;
6
using System.Windows.Controls.Primitives;
7
using System.Windows.Documents;
8
using System.Windows.Input;
9
using System.Windows.Media;
10
using System.Windows.Markup;
11
using System.Windows.Media.Animation;
12
using System.Windows.Shapes;
13
using System.Collections.ObjectModel;
14
15
namespace ZWebClient.UIControls.Charting
16

{
17
[ContentProperty("Segments")]
18
public class GPieChart : Canvas
19
{
20
private PieLayoutManager layoutManager;
21
22
public delegate void ClickedDelegate(object sender, RoutedEventArgs e);
23
public event ClickedDelegate PieClicked;
24
25
public void RaisePieClicked(object sender, RoutedEventArgs e)
26
{
27
if (PieClicked != null)
28
PieClicked(sender, e);
29
}
30
31
public GPieChart()
32
{
33
this.layoutManager = new PieLayoutManager(this);
34
this.SizeChanged += delegate
{ PerformLayout(); };
35
36
this.Segments = new PieSegmentList();
37
this.Segments.CollectionChanged += delegate
{ PerformLayout(); };
38
39
this.SizeChanged += (ss, ee) =>
40
{
41
layoutManager.LayoutChart();
42
};
43
}
44
45
internal void showDataTip(string tip, Point orig)
46
{
47
if (this.DataTip != null)
48
{
49
//this.DataTip._tip.Width = 100;
50
this.DataTip.ShowDataTip(tip, orig);
51
}
52
}
53
54
internal void hideDataTip()
55
{
56
if (this.DataTip != null)
57
this.DataTip.HideDataTip();
58
}
59
60
private void PerformLayout()
61
{
62
layoutManager.LayoutChart();
63
//layoutManager.PlayAnimation();
64
if (this.DataTip != null)
65
{
66
this.DataTip.HideDataTip();
67
}
68
69
}
70
71
Dependency Properties#region Dependency Properties
72
73
public static readonly DependencyProperty DataTipProperty =
74
DependencyProperty.Register("DataTip", typeof(GDataTip), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
75
76
public static readonly DependencyProperty SegmentsProperty =
77
DependencyProperty.Register("Segments", typeof(PieSegmentList), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
78
79
public static readonly DependencyProperty CenterProperty =
80
DependencyProperty.Register("Center", typeof(Point), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
81
82
public static readonly DependencyProperty RadiusProperty =
83
DependencyProperty.Register("Radius", typeof(double), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
84
85
public static readonly DependencyProperty StrokeProperty =
86
DependencyProperty.Register("Stroke", typeof(Brush), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
87
88
public static readonly DependencyProperty StrokeThicknessProperty =
89
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
90
91
public static readonly DependencyProperty FontSizeProperty =
92
DependencyProperty.Register("FontSize", typeof(double), typeof(GPieChart), new PropertyMetadata(OnDependencyPropertyChanged));
93
94
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
95
{
96
GPieChart source = d as GPieChart;
97
source.PerformLayout();
98
if (source.DataTip != null)
99
{
100
source.DataTip.HideDataTip();
101
}
102
}
103
104
105
public GDataTip DataTip
106
{
107
get
{ return (GDataTip)GetValue(DataTipProperty); }
108
set
{ SetValue(DataTipProperty, value); value.SetActiveCanvas(this); }
109
}
110
111
public PieSegmentList Segments
112
{
113
get
{ return (PieSegmentList)GetValue(SegmentsProperty); }
114
set
{ SetValue(SegmentsProperty, value); }
115
}
116
117
public Point Center
118
{
119
get
{ return (Point)GetValue(CenterProperty); }
120
set
{ SetValue(CenterProperty, value); }
121
}
122
123
public double Radius
124
{
125
get
{ return (double)GetValue(RadiusProperty); }
126
set
{ SetValue(RadiusProperty, value); }
127
}
128
129
public Brush Stroke
130
{
131
get
{ return (Brush)GetValue(StrokeProperty); }
132
set
{ SetValue(StrokeProperty, value); }
133
}
134
135
public double StrokeThickness
136
{
137
get
{ return (double)GetValue(StrokeThicknessProperty); }
138
set
{ SetValue(StrokeThicknessProperty, value); }
139
}
140
141
public double FontSize
142
{
143
get
{ return (double)GetValue(FontSizeProperty); }
144
set
{ SetValue(FontSizeProperty, value); }
145
}
146
147
#endregion
148
}
149
150
public class PieSegment
151
{
152
public PieSegment()
153
{
154
this.HasTransformed = false;
155
this.ShowDataTip = true;
156
this.LittleThan30Degrees = false;
157
}
158
159
public double Percentage
160
{
161
get
{ return (this.Degrees / 360.0) * 100.0; }
162
set
{ this.Degrees = 360.0 * (value / 100.0); }
163
}
164
public double Degrees
{ get; set; }
165
public Brush Foreground
{ get; set; }
166
public Brush HighlightForeground
{ get; set; }
167
public Brush DataLabelForeground
{ get; set; }
168
public int DataLabelFontSize
{ get; set; }
169
public FontWeight DataLabelFontWeight
{ get; set; }
170
public string DataLabel
{ get; set; }
171
public bool ShowDataLabel
{ get; set; }
172
public bool ShowDataTip
{ get; set; }
173
public string DataTipString
{ get; set; }
174
public bool HasTransformed
{ get; set; }
175
public bool LittleThan30Degrees
{ get; set; }
176
public BiPieChart ParentChart
{ get; set; }
177
public bool IsMultiPieChartSegment
{ get; set; }
178
}
179
180
public class PieSegmentList : ObservableCollection<PieSegment>
181
{
182
public double TotalDegrees
183
{
184
get
{ return this.Sum(x => x.Degrees); }
185
}
186
}
187
188
internal class PieLayoutManager
189
{
190
private GPieChart pieChart;
191
192
internal PieLayoutManager(GPieChart targetPieChart)
193
{
194
195
if (targetPieChart == null)
196
{
197
throw new ArgumentNullException("targetPieChart");
198
}
199
200
this.pieChart = targetPieChart;
201
}
202
203
private double radius; private Point center;
204
205
internal bool setDefaults()
206
{
207
bool result = true;
208
209
if (double.IsNaN(this.pieChart.ActualHeight))
210
return false;
211
212
if (this.pieChart.ActualHeight <= 0)
213
return false;
214
215
if (double.IsNaN(this.pieChart.ActualWidth))
216
return false;
217
218
if (this.pieChart.ActualWidth <= 0)
219
return false;
220
221
double minSize = (this.pieChart.ActualWidth > this.pieChart.ActualHeight) ? this.pieChart.ActualHeight : this.pieChart.ActualWidth;
222
223
this.center = new Point(this.pieChart.ActualWidth / 2, this.pieChart.ActualHeight / 2);
224
this.radius = minSize / 2;
225
226
return result;
227
228
}
229
230
internal void LayoutChart()
231
{
232
if (Math.Abs(this.pieChart.Segments.TotalDegrees) > 360)
233
{
234
throw new InvalidOperationException("Total Degrees for PieChart cannot be greater than 360° or less than -360°");
235
}
236
237
if (!setDefaults())
238
return;
239
240
this.pieChart.Children.Clear();
241
242
double startAngle = 0.0;
243
244
LabelLocations = new List<string>();
245
246
foreach (PieSegment segment in this.pieChart.Segments)
247
{
248
double endAngle = startAngle + segment.Degrees;
249
250
LayoutSegment(startAngle, endAngle, segment);
251
252
startAngle = endAngle;
253
254
}
255
256
}
257
258
List<string> LabelLocations;
259
260
private void LayoutSegment(double startAngle, double endAngle, PieSegment segment)
261
{
262
startAngle = startAngle > 360 ? 360 : startAngle;
263
endAngle = endAngle > 360 ? 360 : endAngle;
264
TextBlock dataLabel = new TextBlock(); // for data label
265
dataLabel.Tag = segment.DataLabel;
266
dataLabel.IsHitTestVisible = false;
267
dataLabel.Text = segment.DataLabel;
268
dataLabel.FontSize = segment.DataLabelFontSize;
269
dataLabel.Foreground = segment.DataLabelForeground;
270
dataLabel.FontWeight = segment.DataLabelFontWeight;
271
272
double distinct = segment.ShowDataTip == true ? 0 : 4;
273
if (startAngle == 0 && endAngle == 360)
274
{
275
// draw the whole ellipse
276
this.pieChart.Children.Clear();
277
Ellipse e = new Ellipse();
278
e.Width = (this.radius - distinct) * 2;
279
e.Height = (this.radius - distinct) * 2;
280
e.Stroke = this.pieChart.Stroke;
281
e.StrokeThickness = this.pieChart.StrokeThickness;
282
e.Fill = segment.Foreground;
283
284
this.pieChart.Children.Add(e);
285
Canvas.SetLeft(e, this.center.X - this.radius + distinct);
286
Canvas.SetTop(e, this.center.Y - this.radius + distinct);
287
this.pieChart.Children.Add(dataLabel);
288
Canvas.SetLeft(dataLabel, this.radius - distinct);
289
Canvas.SetTop(dataLabel, this.radius - distinct);
290
291
if (segment.ShowDataTip)
292
{
293
if (!segment.IsMultiPieChartSegment && segment.ParentChart.Name != "piePndMsg")
294
{
295
e.Cursor = Cursors.Hand;
296
}
297
e.MouseEnter += delegate
298
{
299
e.Fill = segment.HighlightForeground;
300
Point p = new Point(this.center.X, this.center.Y);
301
this.pieChart.showDataTip(segment.DataTipString, p);
302
};
303
e.MouseLeave += delegate
304
{
305
e.Fill = segment.Foreground;
306
this.pieChart.hideDataTip();
307
};
308
e.MouseLeftButtonDown += delegate
309
{
310
this.pieChart.RaisePieClicked(segment, new RoutedEventArgs()
{ });
311
};
312
}
313
return;
314
}
315
else if (startAngle == 360 && endAngle == 360)
316
{
317
return;
318
}
319
320
double newX = 0;
321
double newY = 0;
322
double prevDegree = startAngle;
323
double angle = segment.Degrees;
324
325
newX = this.center.X + (this.radius - distinct) * Math.Sin((prevDegree + angle) * Math.PI / 180);
326
newY = this.center.Y - (this.radius - distinct) * Math.Cos((prevDegree + angle) * Math.PI / 180);
327
328
Path path = new Path();
329
330
Brush pathStroke = this.pieChart.Stroke;
331
Brush pieFill = segment.Foreground;
332
path.Stroke = pathStroke;
333
path.StrokeThickness = this.pieChart.StrokeThickness;
334
path.Fill = pieFill;
335
PathGeometry geo = new PathGeometry();
336
337
PathFigureCollection figures = new PathFigureCollection();
338
PathFigure figure = new PathFigure();
339
340
PathSegmentCollection lines = new PathSegmentCollection();
341
LineSegment line = new LineSegment();
342
343
figure.StartPoint = this.center;
344
345
Point startP = GetCircumferencePoint(startAngle, this.radius - distinct);
346
347
line.Point = startP;
348
lines.Add(line);
349
350
ArcSegment activePie = new ArcSegment();
351
352
if (angle >= 180)
353
activePie.IsLargeArc = true;
354
else
355
activePie.IsLargeArc = false;
356
357
Point endPoint = new Point(newX, newY);
358
activePie.Point = endPoint;
359
360
activePie.Size = new Size(this.radius - distinct, this.radius - distinct);
361
activePie.SweepDirection = SweepDirection.Clockwise;
362
363
lines.Add(activePie);
364
365
line = new LineSegment();
366
line.Point = this.center;
367
lines.Add(line);
368
369
figure.Segments = lines;
370
figures.Add(figure);
371
geo.Figures = figures;
372
path.Data = geo;
373
374
if (!segment.IsMultiPieChartSegment && segment.ParentChart.Name != "piePndMsg" && segment.ShowDataTip == true)
375
{
376
path.Cursor = Cursors.Hand;
377
}
378
379
mouse event#region mouse event
380
path.MouseLeftButtonDown += delegate
381
{
382
//if (segment.HasTransformed)
383
//{
384
// path.RenderTransform = null;
385
// dataLabel.RenderTransform = null;
386
// segment.HasTransformed = false;
387
//}
388
//else
389
//{
390
// TranslateTransform tt = new TranslateTransform();
391
// Point transBy = GetCircumferencePoint((startAngle + endAngle) / 2.0, 20.0);
392
// Point translate = new Point(transBy.X - this.center.X, transBy.Y - this.center.Y);
393
394
// tt.X = translate.X; tt.Y = translate.Y;
395
// path.RenderTransform = tt;
396
// dataLabel.RenderTransform = tt;
397
398
// segment.HasTransformed = true;
399
//}
400
if (segment.ShowDataTip)
401
{
402
this.pieChart.RaisePieClicked(segment, new RoutedEventArgs()
{ });
403
}
404
405
};
406
//path.MouseLeftButtonUp += delegate
407
//{
408
// if (!segment.IsMultiPieChartSegment && segment.ShowDataTip)
409
// {
410
// this.pieChart.RaisePieClicked(segment, new RoutedEventArgs() { });
411
// }
412
//};
413
414
path.MouseEnter += (dd,ee)=>
415
{
416
path.Fill = segment.HighlightForeground;
417
418
419
double sFactor = segment.Degrees / 2.1;
420
double tX = this.center.X + this.radius * 0.5 * Math.Sin((endAngle - sFactor) * Math.PI / 180);
421
double tY = this.center.Y - this.radius * 0.5 * Math.Cos((endAngle - sFactor) * Math.PI / 180);
422
423
424
425
Point orig = new Point(tX, tY);
426
427
if (path.RenderTransform != null)
428
{
429
TranslateTransform tt = path.RenderTransform as TranslateTransform;
430
if (tt != null)
431
{
432
orig = tt.Transform(orig);
433
}
434
}
435
436
if (segment.ShowDataTip)
437
this.pieChart.showDataTip(segment.DataTipString, orig);
438
};
439
440
path.MouseLeave += delegate
441
{
442
path.Fill = segment.Foreground;
443
this.pieChart.hideDataTip();
444
};
445
#endregion
446
447
this.pieChart.Children.Add(path);
448
if (segment.ShowDataLabel)
449
{
450
double labelAngle = (segment.LittleThan30Degrees == true ? 40 : segment.Percentage * 3.60) / 2.1;
451
double dX = -12;
452
double dY = -5;
453
double sF = 0.58;
454
455
newX = this.center.X + this.radius * sF * Math.Sin((startAngle + labelAngle) * Math.PI / 180) + dX;
456
newY = this.center.Y - this.radius * sF * Math.Cos((startAngle + labelAngle) * Math.PI / 180) + dY;
457
458
path.Tag = segment.DataLabel;
459
this.pieChart.Children.Add(dataLabel);
460
Canvas.SetLeft(dataLabel, newX);
461
Canvas.SetTop(dataLabel, newY);
462
463
}
464
465
}
466
467
//private Point GetCircumferencePoint(double angle, double radius)
468
//{
469
// return GetCircumferencePoint(angle, radius);
470
471
//}
472
473
private Point GetCircumferencePoint(double angle, double radius)
474
{
475
double angleRad = (Math.PI / 180.0) * angle;
476
477
double x = this.center.X + radius * Math.Sin(angleRad);
478
double y = this.center.Y - radius * Math.Cos(angleRad);
479
480
return new Point(x, y);
481
}
482
}
483
}
484
485