Silverlight 3: 3D ImageGrid erstellen


Ich habe vor einigen Tagen eine sehr nette Anwendung zum Betrachten von Fotos im Browser gesehen. Der Nachtteil bei der Anwendung war allerdings, das man vorher ein spezielles Plug-In (weder Flash noch Silverlight) installieren musste um sich das ganze zu Betrachten. Außerdem war es sehr groß … 🙁

Das geht leichter und einfacher und noch viel dynamischer dachte ich mir und habe deshalb mal ein eigenes Container-Control (ImageGrid) erstellt.

image

Schritt 1: Ableiten von der richtigen Klasse –> Panel

   1: public class ImageGrid : Panel
   2: {
   3:     protected override Size ArrangeOverride(Size finalSize)
   4:     {
   5:         double imageWidth = (double)this.GetValue(ImageWidthProperty);
   6:         double imageHeight = (double)this.GetValue(ImageHeightProperty);
   7:         int rowsPerColumn = (int)this.GetValue(RowsPerColumnProperty);
   8:         double imageMargin = (double)this.GetValue(ImageMarginProperty);
   9:  
  10:         int currentRow = 0;
  11:         int currentColumn = 0;
  12:  
  13:         foreach (Image image in this.Children.OfType<Image>())
  14:         {
  15:             Hover3DBehavior behavior = new Hover3DBehavior();
  16:             behavior.ZHoverValue = (double)this.GetValue(ZHoverValueProperty);
  17:             behavior.Attach(image);
  18:  
  19:             if ((bool)this.GetValue(ShowShadowProperty))
  20:             {
  21:                 DropShadowEffect ds = new DropShadowEffect();
  22:                 ds.Opacity = .3;
  23:                 ds.BlurRadius = 10.0;
  24:                 ds.Direction = 0.0;
  25:                 ds.ShadowDepth = 20.0;
  26:                 image.Effect = ds;
  27:             }
  28:  
  29:             Rect rect = new Rect(
  30:                 currentColumn * (imageWidth + imageMargin),
  31:                 currentRow * (imageHeight + imageMargin),
  32:                 imageWidth,
  33:                 imageHeight);
  34:  
  35:             image.Width = imageWidth;
  36:             image.Height = imageHeight;
  37:             image.Arrange(rect);
  38:             image.InvalidateArrange();
  39:  
  40:             currentRow++;
  41:             if (currentRow >= rowsPerColumn)
  42:             {
  43:                 currentRow = 0;
  44:                 currentColumn++;
  45:             }
  46:         }
  47:  
  48:         Size newSize = new Size((currentColumn+1) * (imageWidth + imageMargin), rowsPerColumn * (imageHeight+imageMargin));
  49:  
  50:         return base.ArrangeOverride(newSize);
  51:     }
  52: }

Schritt 2: Erweitern mit netten Eigenschaften zum Konfigurieren

   1: private const int C_DefaultRowsPerColumn = 5;
   2: private const double C_DefaultImageWidth = 160.0;
   3: private const double C_DefaultImageHeight = 120.0;
   4: private const double C_DefaultZHover = 200.0;
   5: private const bool C_DefaultShowShadow = true;
   6: private const double C_DefaultImageMargin = 8.0;
   7:  
   8: #region Images per column
   9:  
  10: public int RowsPerColumn
  11: {
  12:     get { return (int)GetValue(RowsPerColumnProperty); }
  13:     set { SetValue(RowsPerColumnProperty, value); }
  14: }
  15:  
  16: public static readonly DependencyProperty RowsPerColumnProperty =
  17:         DependencyProperty.Register("RowsPerColumn", typeof(int),
  18:         typeof(ImageGrid),
  19:         new PropertyMetadata(C_DefaultRowsPerColumn,
  20:         new PropertyChangedCallback(OnImageSizeChanged)));
  21:  
  22: #endregion
  23:  
  24: #region Image Width
  25:  
  26: public double ImageWidth
  27: {
  28:     get { return (double)GetValue(ImageWidthProperty); }
  29:     set { SetValue(ImageWidthProperty, value); }
  30: }
  31:  
  32: public static readonly DependencyProperty ImageWidthProperty =
  33:         DependencyProperty.Register("ImageWidth", typeof(double),
  34:         typeof(ImageGrid),
  35:         new PropertyMetadata(C_DefaultImageWidth,
  36:         new PropertyChangedCallback(OnImageSizeChanged)));
  37:  
  38: #endregion
  39:  
  40: #region Image Margin
  41:  
  42: public double ImageMargin
  43: {
  44:     get { return (double)GetValue(ImageMarginProperty); }
  45:     set { SetValue(ImageMarginProperty, value); }
  46: }
  47:  
  48: public static readonly DependencyProperty ImageMarginProperty =
  49:         DependencyProperty.Register("ImageMargin", typeof(double),
  50:         typeof(ImageGrid),
  51:         new PropertyMetadata(C_DefaultImageMargin,
  52:         new PropertyChangedCallback(OnImageSizeChanged)));
  53:  
  54: #endregion
  55:  
  56: #region Image Height
  57:  
  58: public double ImageHeight
  59: {
  60:     get { return (double)GetValue(ImageHeightProperty); }
  61:     set { SetValue(ImageHeightProperty, value); }
  62: }
  63:  
  64: public static readonly DependencyProperty ImageHeightProperty =
  65:         DependencyProperty.Register("ImageHeight", typeof(double),
  66:         typeof(ImageGrid),
  67:         new PropertyMetadata(C_DefaultImageHeight,
  68:         new PropertyChangedCallback(OnImageSizeChanged)));
  69:  
  70: protected static void OnImageSizeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  71: {
  72:     ImageGrid i = obj as ImageGrid;
  73:     i.InvalidateArrange();
  74: }
  75:  
  76: #endregion
  77:  
  78: #region ZHoverValue 
  79:  
  80: public double ZHoverValue
  81: {
  82:     get { return (double)GetValue(ZHoverValueProperty); }
  83:     set { SetValue(ZHoverValueProperty, value); }
  84: }
  85:  
  86: public static readonly DependencyProperty ZHoverValueProperty =
  87:     DependencyProperty.Register("ZHoverValue", typeof(double), typeof(ImageGrid),
  88:     new PropertyMetadata((double)C_DefaultZHover, null));
  89:  
  90: #endregion
  91:  
  92: #region Show Shadow
  93:  
  94: public bool ShowShadow
  95: {
  96:     get { return (bool)GetValue(ShowShadowProperty); }
  97:     set { SetValue(ShowShadowProperty, value); }
  98: }
  99:  
 100: public static readonly DependencyProperty ShowShadowProperty =
 101:     DependencyProperty.Register("ShowShadow", typeof(bool), typeof(ImageGrid),
 102:     new PropertyMetadata((bool)C_DefaultShowShadow, new PropertyChangedCallback(OnImageSizeChanged)));
 103:  
 104: #endregion

Schritt 4: Erstellen eines Hover-Effektes mithilfe eines Behaviors

   1: public class Hover3DBehavior : Behavior<UIElement>
   2: {
   3:     PlaneProjection _planeProjection;
   4:  
   5:     public Hover3DBehavior()
   6:         : base()
   7:     {
   8:        
   9:     }
  10:  
  11:     Storyboard _hoverMe;
  12:     Storyboard _unhoverMe;
  13:  
  14:     private const double C_DefaultHoverValue = 500.0;
  15:  
  16:     #region ZHoverValue 
  17:  
  18:     public double ZHoverValue
  19:     {
  20:         get { return (double)GetValue(ZHoverValueProperty); }
  21:         set { SetValue(ZHoverValueProperty, value); }
  22:     }
  23:  
  24:     public static readonly DependencyProperty ZHoverValueProperty =
  25:         DependencyProperty.Register("ZHoverValue", typeof(double), typeof(Hover3DBehavior),
  26:         new PropertyMetadata((double)C_DefaultHoverValue, null));
  27:  
  28:     #endregion
  29:  
  30:     #region Overrides 
  31:  
  32:     protected override void OnAttached()
  33:     {
  34:         base.OnAttached();
  35:  
  36:         _planeProjection = new PlaneProjection();
  37:         this.AssociatedObject.Projection = _planeProjection;
  38:  
  39:         if (!DesignerProperties.GetIsInDesignMode(this))
  40:         {
  41:             _hoverMe = new Storyboard();
  42:  
  43:             DoubleAnimation da1 = new DoubleAnimation();
  44:  
  45:             _hoverMe.Children.Add(da1);
  46:             da1.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, 300));
  47:             da1.To = this.ZHoverValue;
  48:             Storyboard.SetTarget(da1, this.AssociatedObject);
  49:             Storyboard.SetTargetProperty(da1, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)"));
  50:  
  51:             DoubleAnimation da2 = new DoubleAnimation();
  52:             BounceEase be2 = new BounceEase();
  53:             be2.EasingMode = EasingMode.EaseOut;
  54:             be2.Bounces = 3;
  55:             da2.EasingFunction = be2;
  56:  
  57:             _unhoverMe = new Storyboard();
  58:             _unhoverMe.Children.Add(da2);
  59:             da2.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, 1000));
  60:             da2.To = 0.0;
  61:             Storyboard.SetTarget(da2, this.AssociatedObject);
  62:             Storyboard.SetTargetProperty(da2, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)"));
  63:  
  64:             if ((this.AssociatedObject as FrameworkElement).Resources.Contains("hoverme"))
  65:             {
  66:                 (this.AssociatedObject as FrameworkElement).Resources.Remove("hoverme");
  67:             }
  68:             (this.AssociatedObject as FrameworkElement).Resources.Add("hoverme", _hoverMe);
  69:             
  70:             if ((this.AssociatedObject as FrameworkElement).Resources.Contains("unhoverme"))
  71:             {
  72:                 (this.AssociatedObject as FrameworkElement).Resources.Remove("unhoverme");
  73:             }
  74:             (this.AssociatedObject as FrameworkElement).Resources.Add("unhoverme", _unhoverMe);
  75:         }
  76:         
  77:         this.AssociatedObject.MouseEnter += new MouseEventHandler(AssociatedObject_MouseEnter);
  78:         this.AssociatedObject.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);
  79:     }
  80:  
  81:     protected override void OnDetaching()
  82:     {
  83:         base.OnDetaching();
  84:  
  85:         this.AssociatedObject.Projection = null;
  86:         _planeProjection = null;
  87:  
  88:         this.AssociatedObject.MouseEnter -= new MouseEventHandler(AssociatedObject_MouseEnter);
  89:         this.AssociatedObject.MouseLeave -= new MouseEventHandler(AssociatedObject_MouseLeave);
  90:     }
  91:  
  92:     #endregion
  93:  
  94:     #region Events
  95:  
  96:     void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
  97:     {
  98:         _unhoverMe.Begin();
  99:     }
 100:  
 101:     void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
 102:     {
 103:         _hoverMe.Begin();
 104:     }
 105:  
 106:     #endregion
 107:  
 108: }

Schritt 3: Verwenden in Blend

Das ImageGrid nach dem ich einige Beispielbilder reingesetzt habe.

image

Der Arbeitsbereich

image

Der VisualTree.

 image

Die zusätzlichen Konfigurationsmöglichkeiten.

Comments (0)