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


{17
[ContentProperty("Segments")]18
public class GPieChart : Canvas19

{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 Properties72

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 DataTip106

{107

get
{ return (GDataTip)GetValue(DataTipProperty); }108

set
{ SetValue(DataTipProperty, value); value.SetActiveCanvas(this); }109
}110

111
public PieSegmentList Segments112

{113

get
{ return (PieSegmentList)GetValue(SegmentsProperty); }114

set
{ SetValue(SegmentsProperty, value); }115
}116

117
public Point Center118

{119

get
{ return (Point)GetValue(CenterProperty); }120

set
{ SetValue(CenterProperty, value); }121
}122

123
public double Radius124

{125

get
{ return (double)GetValue(RadiusProperty); }126

set
{ SetValue(RadiusProperty, value); }127
}128

129
public Brush Stroke130

{131

get
{ return (Brush)GetValue(StrokeProperty); }132

set
{ SetValue(StrokeProperty, value); }133
}134

135
public double StrokeThickness136

{137

get
{ return (double)GetValue(StrokeThicknessProperty); }138

set
{ SetValue(StrokeThicknessProperty, value); }139
}140

141
public double FontSize142

{143

get
{ return (double)GetValue(FontSizeProperty); }144

set
{ SetValue(FontSizeProperty, value); }145
}146

147
#endregion148
}149

150
public class PieSegment151

{152
public PieSegment()153

{154
this.HasTransformed = false;155
this.ShowDataTip = true;156
this.LittleThan30Degrees = false;157
}158

159
public double Percentage160

{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 TotalDegrees183

{184

get
{ return this.Sum(x => x.Degrees); }185
}186
}187

188
internal class PieLayoutManager189

{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 label265
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 ellipse276
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 += delegate298

{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 += delegate304

{305
e.Fill = segment.Foreground;306
this.pieChart.hideDataTip();307
};308
e.MouseLeftButtonDown += delegate309

{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
else355
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 event380
path.MouseLeftButtonDown += delegate381

{382
//if (segment.HasTransformed)383
//{384
// path.RenderTransform = null;385
// dataLabel.RenderTransform = null;386
// segment.HasTransformed = false;387
//}388
//else389
//{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 += delegate407
//{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 += delegate441

{442
path.Fill = segment.Foreground;443
this.pieChart.hideDataTip();444
};445
#endregion446

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

浙公网安备 33010602011771号