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.