Nichts leichter als das.

image

Da ich inzwischen einige Controls erstellt habe, arbeite ich ganz gerne mit Vererbung und meine Basisklasse für das Carousel ist der BaseContainer:

   1: using System.Windows.Controls;
   2: using System.Windows;
   3:  
   4: namespace Oliver.Controls
   5: {
   6:     public partial class BaseContainer : Panel
   7:     {
   8:         #region ItemWidth
   9:  
  10:         public double ItemWidth
  11:         {
  12:             get { return (double)GetValue(ItemWidthProperty); }
  13:             set { SetValue(ItemWidthProperty, value); }
  14:         }
  15:  
  16:         public static readonly DependencyProperty ItemWidthProperty =
  17:             DependencyProperty.Register("ItemWidth", typeof(double), typeof(BaseContainer), 
  18:             new PropertyMetadata(100.0, OnItemWidthChanged));
  19:  
  20:         private static void OnItemWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  21:         {
  22:             BaseContainer baseContainer = d as BaseContainer;
  23:             baseContainer.InvalidateArrange();
  24:         }
  25:  
  26:         #endregion 
  27:  
  28:         #region ItemHeight
  29:  
  30:         public double ItemHeight
  31:         {
  32:             get { return (double)GetValue(ItemHeightProperty); }
  33:             set { SetValue(ItemHeightProperty, value); }
  34:         }
  35:  
  36:         public static readonly DependencyProperty ItemHeightProperty =
  37:             DependencyProperty.Register("ItemHeight", typeof(double), typeof(BaseContainer),
  38:             new PropertyMetadata(100.0, OnItemHeightChanged));
  39:  
  40:         private static void OnItemHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  41:         {
  42:             BaseContainer baseContainer = d as BaseContainer;
  43:             baseContainer.InvalidateArrange();
  44:         }
  45:  
  46:         #endregion
  47:  
  48:         
  49:     }
  50: }

Die Datei BaseContainer.cs

Sie enthält zwei Eigenschaften “ItemWidth” und “ItemHeight” die ich in allen Container-Controls immer wieder benötigte, daher kommen diese in die “Masterklasse”.

In Wirklichkeit ist dies eine WPF-Klasse die ich in meinen Silverlight-Controls ebenfalls verwende und als Referenz einbinde. Für gewisse Effekte benötige ich dann auch noch immer wieder gerne die aktuelle Framerate des Plug-Ins. Diese Funktion kann allerdings WPF nicht auf meine gewünschte Art und Weise. Deshalb erweitere ich die BaseContainer-Klasse mittels Partial Class um ein Feature:

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Controls;
   4:  
   5: namespace Oliver.Controls
   6: {
   7:     public partial class BaseContainer : Panel
   8:     {
   9:         public TimeSpan FrameRate
  10:         {
  11:             get 
  12:             {
  13:                 return GetFrameRate();
  14:             }
  15:         }
  16:  
  17:         public static int FramesPerSecond
  18:         {
  19:             get { return 1000 / Application.Current.Host.Settings.MaxFrameRate; }
  20:         }
  21:  
  22:         public static TimeSpan GetFrameRate()
  23:         {
  24:             int ms = FramesPerSecond;
  25:             return TimeSpan.FromMilliseconds(ms); 
  26:         }
  27:     }
  28: }

Die Datei BaseContainer.Silverlight.cs

Das eigentliche Logik für das Carousel kommt in die Carousel.cs-Datei.

Dabei sind zwei Methoden besonders wichtig: MeasureOverride und ArrangeOverride

MeasureOverride –> Diese sagt jedem Element im Panel, das sich die “Kinder” des Elements an die neue Größe anzupassen haben …

   1: protected override Size MeasureOverride(Size availableSize)
   2: {
   3:     foreach (UIElement element in Children)
   4:     {
   5:         element.Measure(new Size(ItemWidth, ItemHeight));
   6:     }
   7:     return availableSize;
   8: }

ArrangeOverride –> Ordnet die Elemente im Panel neu an. In unserem Fall, wird der Winkel der Elemente berechnet, an dem die einzelnen Elemente stehen.

   1: protected override Size ArrangeOverride(System.Windows.Size finalSize)
   2: {
   3:     for (int i = 0; i < Children.Count; i++)
   4:     {
   5:         // Calculate and set angle of all children
   6:         double angle = i * (Math.PI * 2) / Children.Count;
   7:         Children[i].SetValue(CarouselPanel.AngleProperty, angle);
   8:     }
   9:     DoArrange();
  10:  
  11:     return base.ArrangeOverride(finalSize);
  12: }

Die Methode DoArrange() sorgt dafür das sich das ganze auch noch drehen kann.

   1: void DoArrange()
   2: {
   3:     double height = this.DesiredSize.Height;
   4:     double width = this.DesiredSize.Width;
   5:  
   6:     Point center = new Point((width - ItemWidth) / 2, (height - ItemHeight) / 2);
   7:     double radiusX = center.X;
   8:     double radiusY = center.Y; 
   9:     double scale = ScalePerspective; 
  10:  
  11:     for (int i = 0; i < Children.Count; i++)
  12:     {
  13:         UIElement item = Children[i];
  14:  
  15:         double current = (double)item.GetValue(CarouselPanel.AngleProperty);
  16:         double angle = current + (_internalSpeed * (3 / 360.0) * (2 * Math.PI));
  17:         item.SetValue(CarouselPanel.AngleProperty, angle);
  18:         double radians = angle;
  19:  
  20:         Point p = new Point(
  21:             (Math.Cos(radians) * radiusX) + center.X,
  22:             (Math.Sin(radians) * radiusY) + center.Y);
  23:     
  24:         if (item.RenderTransform == null || 
  25:             (!(item.RenderTransform is ScaleTransform)))
  26:         {
  27:             item.RenderTransform = new ScaleTransform();
  28:         }
  29:         
  30:         ScaleTransform sc = item.RenderTransform as ScaleTransform;
  31:  
  32:         double scaleMinusRounding  = p.Y / (center.Y + radiusY); 
  33:         sc.ScaleX = sc.ScaleY =  Math.Min(scaleMinusRounding + scale, 1.0) ; 
  34:  
  35:         int zIndex = (int) ((p.Y / this.Height) * 50);                   
  36:         item.SetValue(Canvas.ZIndexProperty, zIndex);
  37:  
  38:         Rect r = new Rect(p.X, p.Y, ItemWidth, ItemHeight);
  39:         item.Arrange(r);
  40:         item.InvalidateArrange();
  41:      }
  42: }

Den vollständigen Code kann man unter www.the-oliver.com herunterladen.

Das Ergebnis sieht wie folgt aus:

Get Microsoft Silverlight