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.
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.
Der Arbeitsbereich
Der VisualTree.
Die zusätzlichen Konfigurationsmöglichkeiten.