Coding4Fun-Artikel: Windows Phone Picture Effects Application
Rene Schulte hat wieder zugeschlagen, diesmal bringt er Grafikeffekte auf Windows Phone 7. Im Blog von Coding4Fun hat er dazu einen sehr ausführlichen ersten Artikel veröffentlicht.
Rene Schulte hat wieder zugeschlagen, diesmal bringt er Grafikeffekte auf Windows Phone 7. Im Blog von Coding4Fun hat er dazu einen sehr ausführlichen ersten Artikel veröffentlicht.
Auf der Website: http://developforwindows.com/ gibt es einige sehr coole Beispielanwendung für die Anwendungsenwicklung unter Windows 7.
Die Anwendung sieht nicht aus wie eine typische "alte” Windows-Anwendung, sondern kommt mit einer sehr ansprechenden, individuellen Oberfläche daher. In der Anwendung sind diverse Bücher enthalten, die man einfach aus einem Bücherregal herauspicken und lesen kann.
Macht wirklich Spaß und das coolste ist, der Sourcecode ist frei mit dabei.
A great feature in Silverlight 3 is the capability to install applications out-of-browser. For those applications it is very useful to check, whether there is an update at the original location, where they are coming from.
My simple application checks this using behaviors, which can be reused for any applications. Just one feature is very important to enable –> The Out-Of-Browser Feature in your application.
The install-Behavior checks the Install-State of the application, and hide the control which contains the Install-Feature, if it is already installed.
The in-browser version, with an Install button.
The same application after installing it local.
The out-of-browser-application without the install button (because, it is already installed
)
The Update Dialog, when an update is available. You will not see this feature in the preview, because I will not update it regularly.
No code needed in your application
XAML-Code
<UserControl x:Class="SmallTextEditor.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver="clr-namespace:TheOliver.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <TheOliver:CheckForUpdateBehavior /> </i:EventTrigger> </i:Interaction.Triggers> <Grid.RowDefinitions> <RowDefinition Height="28*" /> <RowDefinition Height="272*" /> </Grid.RowDefinitions> <RichTextBox x:Name="_textbox" Grid.Row="1" IsEnabled="False" /> <StackPanel HorizontalAlignment="Left" Name="stackPanel1" Orientation="Horizontal"> <Button Content="New" Height="23" Name="_new" IsEnabled="False" /> <Button Content="Open" Height="23" Name="_open" IsEnabled="False" /> <Button Content="Save" Height="23" Name="_save" IsEnabled="False" /> <Button Content="Install Local" Height="23" Name="_install"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver:InstallOutOfBrowserBehavior /> </i:EventTrigger> </i:Interaction.Triggers> </Button> </StackPanel> </Grid> </UserControl>
Sourcecode for Install-Out-Of-Browser-Behavior
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Interactivity; using System.Windows.Controls; namespace TheOliver.Controls { public class InstallOutOfBrowserBehavior : TargetedTriggerAction<FrameworkElement> { UIElement _element; protected override void OnAttached() { _element = this.Target as UIElement; if (!Application.Current.IsRunningOutOfBrowser) { Application.Current.InstallStateChanged += (s, e) => { CheckInstallState(); }; CheckInstallState(); if (_element is Button) { (_element as Button).Click += (s, e) => { InstallOOB(); }; } else { _element.MouseLeftButtonDown += (s, e) => { InstallOOB(); }; } } else { _element.Visibility = Visibility.Collapsed; } base.OnAttached(); } private void InstallOOB() { if (Application.Current.InstallState != InstallState.Installed && Application.Current.InstallState != InstallState.Installing) { Application.Current.Install(); } } private void CheckInstallState() { if (Application.Current.InstallState == InstallState.Installed || Application.Current.InstallState == InstallState.Installing) { _element.Visibility = Visibility.Collapsed; } else { _element.Visibility = Visibility.Visible; } } protected override void Invoke(object o) { } } }
Sourcecode for CheckForUpdateBehavior
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Interactivity; namespace TheOliver.Controls { public class CheckForUpdateBehavior : TargetedTriggerAction<FrameworkElement> { UIElement _element; protected override void OnAttached() { // Works only out-of-browser if (Application.Current.IsRunningOutOfBrowser) { _element = this.AssociatedObject as UIElement; } base.OnAttached(); } protected override void Invoke(object o) { if (_element != null) { Application.Current.CheckAndDownloadUpdateCompleted += (s, e) => { if (e.UpdateAvailable) { MessageBox.Show(UpdateIsAvailableMessageText); } }; Application.Current.CheckAndDownloadUpdateAsync(); } } public string UpdateIsAvailableMessageText { get { return (string)GetValue(UpdateIsAvailableMessageTextProperty); } set { SetValue(UpdateIsAvailableMessageTextProperty, value); } } public static readonly DependencyProperty UpdateIsAvailableMessageTextProperty = DependencyProperty.Register( "UpdateIsAvailableMessageText", typeof(string), typeof(CheckForUpdateBehavior), new PropertyMetadata("Update is available. Please restart your application")); } }
Best regards,
The-Oliver
A very cool new feature in Silverlight 3 is the support of perspective 3D. And now image what you can do with 3D, your Mouse and Behaviors. Apply 3D capabilities to every control you like.
Ta da … the Silverlight Mouse 3D Behavior
XAML-Code
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" x:Class="Mouse3DBehavior.MainPage" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Image Source="20080815_114932.jpg" Stretch="Fill"> <i:Interaction.Behaviors> <TheOliver_Controls:Mouse3DBehavior /> </i:Interaction.Behaviors> </Image> </Grid> </UserControl>
Sourcecode
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; using System.Windows.Media; namespace TheOliver.Controls { public class Mouse3DBehavior : Behavior<UIElement> { PlaneProjection _planeProjection; bool _buttonPressed = false; Point _originPoint; UIElement _target; FrameworkElement _control; UIElement _targetParent; double _controlHeight; double _controlWidth; protected override void OnAttached() { base.OnAttached(); _target = this.AssociatedObject; _control = _target as FrameworkElement; _control.LayoutUpdated += (s, e) => { _targetParent = _control.Parent as UIElement; _planeProjection = new PlaneProjection(); _target.Projection = _planeProjection; _targetParent.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); _targetParent.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); _targetParent.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove); _targetParent.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave); _controlHeight = (_targetParent as FrameworkElement).ActualHeight; _controlWidth = (_targetParent as FrameworkElement).ActualWidth; }; } void AssociatedObject_MouseLeave(object sender, MouseEventArgs e) { _buttonPressed = false; } void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { _target.CaptureMouse(); _originPoint = GetPoint(e); _buttonPressed = true; } void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { _buttonPressed = false; _target.ReleaseMouseCapture(); } void AssociatedObject_MouseMove(object sender, MouseEventArgs e) { if (_buttonPressed) { PlaneProjection pp = _target.Projection as PlaneProjection; Point pt = GetPoint(e); double widthPixPerAngle = _controlWidth / 720; double heightPixPerAngle = _controlHeight / 720; double diffY = (pt.X - _controlWidth / 2) * widthPixPerAngle; double diffX = (pt.Y - _controlHeight / 2) * heightPixPerAngle; _originPoint = pt; if (YEnable) { pp.RotationY = diffY; } if (XEnable) { pp.RotationX = diffX; } } } private Point GetPoint(MouseEventArgs e) { Point point = e.GetPosition(_targetParent); return point; } protected override void OnDetaching() { base.OnDetaching(); this.AssociatedObject.Projection = null; _targetParent.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); _targetParent.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); _targetParent.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove); _targetParent.MouseLeave -= new MouseEventHandler(AssociatedObject_MouseLeave); } public double MoveFactor { get { return (double)GetValue(MoveFactorProperty); } set { SetValue(MoveFactorProperty, value); } } public static readonly DependencyProperty MoveFactorProperty = DependencyProperty.Register( "MoveFactor", typeof(double), typeof(Mouse3DBehavior), new PropertyMetadata(1.0)); public bool XEnable { get { return (bool)GetValue(XEnableProperty); } set { SetValue(XEnableProperty, value); } } public static readonly DependencyProperty XEnableProperty = DependencyProperty.Register( "XEnable", typeof(bool), typeof(Mouse3DBehavior), new PropertyMetadata(true)); public bool YEnable { get { return (bool)GetValue(YEnableProperty); } set { SetValue(YEnableProperty, value); } } public static readonly DependencyProperty YEnableProperty = DependencyProperty.Register( "YEnable", typeof(bool), typeof(Mouse3DBehavior), new PropertyMetadata(true)); } }
Deep Zooms are very useful for catalog systems or holiday photos. You can get a big impression of all your images, but when you want to step through each single picture, navigation could get a little bit challenging … until now. Here is a small behavior to step through each single photo in a deep zoom collection.
XAML Code
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" x:Class="DeepZoomMouseBehavior.MainPage" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock Text="Deep Zoom Sample" /> <MultiScaleImage x:Name="_msi" Source="Images/dzc_output.xml" Margin="0,19,0,0"> <i:Interaction.Behaviors> <TheOliver_Controls:DeepZoomBehavior /> </i:Interaction.Behaviors> </MultiScaleImage> <Button x:Name="_home" HorizontalAlignment="Right" VerticalAlignment="Top" Width="53" Content="Home"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomNavigateHomeBehavior TargetName="_msi" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button x:Name="_shuffle" HorizontalAlignment="Right" VerticalAlignment="Top" Width="53" Content="Shuffle" Margin="0,0,57,0"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomRandomImageArrangeBehavior TargetName="_msi" XOffset="1" YOffset="1" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button x:Name="_slideShow" HorizontalAlignment="Right" VerticalAlignment="Top" Width="68" Content="Slideshow" Margin="0,0,114,0"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomSlideShowBehavior TargetName="_msi" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> </Grid> </UserControl>
Sourcecode
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace TheOliver.Controls { public class DeepZoomSlideShowBehavior : TargetedTriggerAction<MultiScaleImage> { private MultiScaleImage _msi; private int _count = 0; private int _totalImages; protected override void Invoke(object o) { if (this._msi == null) { this._msi = this.Target; _totalImages = _msi.SubImages.Count; } if (_count < _totalImages) { ZoomOnImage(_count); } else { _count = 0; ZoomOnImage(_count); } } private void ZoomOnImage(int subImageIndex) { _count++; MultiScaleSubImage subImage = _msi.SubImages[subImageIndex]; double scaleBy = 1 / subImage.ViewportWidth; Rect subImageRect = new Rect(-subImage.ViewportOrigin.X * scaleBy, -subImage.ViewportOrigin.Y * scaleBy, scaleBy, (1 / subImage.AspectRatio) * scaleBy); if ((this._msi.Width / this._msi.Height) > subImage.AspectRatio) { double targetViewportWidth = subImageRect.Height * this._msi.AspectRatio; double targetPointX = (targetViewportWidth - subImageRect.Width) / 2; this._msi.ViewportOrigin = new Point(subImageRect.X - targetPointX, subImageRect.Y); this._msi.ViewportWidth = targetViewportWidth; } else { this._msi.ViewportWidth = subImageRect.Width; this._msi.ViewportOrigin = new Point(subImageRect.X, subImageRect.Y); } } } }
Deep Zooms in Silverlight are great. On key feature is, that you have access to every sub image. So … why don’t we use this with animations?
XAML-Code
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" x:Class="DeepZoomMouseBehavior.MainPage" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock Text="Deep Zoom Sample" /> <MultiScaleImage x:Name="_msi" Source="Images/dzc_output.xml" Margin="0,19,0,0"> <i:Interaction.Behaviors> <TheOliver_Controls:DeepZoomBehavior /> </i:Interaction.Behaviors> </MultiScaleImage> <Button x:Name="_home" HorizontalAlignment="Right" VerticalAlignment="Top" Width="53" Content="Home"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomNavigateHomeBehavior TargetName="_msi" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button x:Name="_shuffle" HorizontalAlignment="Right" VerticalAlignment="Top" Width="53" Content="Shuffle" Margin="0,0,57,0"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomRandomImageArrangeBehavior TargetName="_msi" XOffset="1" YOffset="1" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> </Grid> </UserControl>
Sourcecode
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; using System.Windows.Media.Animation; namespace TheOliver.Controls { public class DeepZoomRandomImageArrangeBehavior : TargetedTriggerAction<MultiScaleImage> { private List<MultiScaleSubImage> _randomList = new List<MultiScaleSubImage>(); int _totalColumns = 0; int _totalRows = 0; private MultiScaleImage _msi; public double XOffset { get { return (double)GetValue(XOffsetProperty); } set { SetValue(XOffsetProperty, value); } } public static readonly DependencyProperty XOffsetProperty = DependencyProperty.Register( "XOffset", typeof(double), typeof(DeepZoomRandomImageArrangeBehavior), new PropertyMetadata(1.25, XOffsetChanged)); private static void XOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { } public double YOffset { get { return (double)GetValue(YOffsetProperty); } set { SetValue(YOffsetProperty, value); } } public static readonly DependencyProperty YOffsetProperty = DependencyProperty.Register( "YOffset", typeof(double), typeof(DeepZoomRandomImageArrangeBehavior), new PropertyMetadata(1.25, YOffsetChanged)); private static void YOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { } public int Speed { get { return (int)GetValue(SpeedProperty); } set { SetValue(SpeedProperty, value); } } public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register( "Speed", typeof(int), typeof(DeepZoomRandomImageArrangeBehavior), new PropertyMetadata(1000, SpeedChanged)); private static void SpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { } protected override void Invoke(object o) { _msi = this.Target; ArrangeIntoGrid(); } private void ArrangeIntoGrid() { _randomList = RandomizedListOfImages(); int totalImagesAdded = 0; double totalWidth = 0; double xoffset = XOffset; double yoffset = YOffset; double margin = .1; if (_randomList.Count > 1) { int numberOfImages = _randomList.Count; _totalColumns = 0; _totalColumns = (int)Math.Ceiling(Math.Sqrt(numberOfImages)); _totalRows = numberOfImages / (_totalColumns - 1); totalWidth = _totalColumns * xoffset; Storyboard moveStoryboard = new Storyboard(); for (int row = 0; row < _totalRows; row++) { for (int col = 0; col < _totalColumns; col++) { if (numberOfImages != totalImagesAdded) { MultiScaleSubImage currentImage = _randomList[totalImagesAdded]; currentImage.ViewportWidth = 1; Point currentPosition = new Point(0, 0); Point futurePosition = new Point(-xoffset * col, -yoffset * row); // Create Animation PointAnimationUsingKeyFrames moveAnimation = new PointAnimationUsingKeyFrames(); // Create Keyframe SplinePointKeyFrame startKeyframe = new SplinePointKeyFrame(); startKeyframe.Value = currentPosition; startKeyframe.KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero); startKeyframe = new SplinePointKeyFrame(); startKeyframe.Value = futurePosition; startKeyframe.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(Speed)); KeySpline ks = new KeySpline(); ks.ControlPoint1 = new Point(0, 1); ks.ControlPoint2 = new Point(1, 1); startKeyframe.KeySpline = ks; moveAnimation.KeyFrames.Add(startKeyframe); Storyboard.SetTarget(moveAnimation, currentImage); Storyboard.SetTargetProperty(moveAnimation, new PropertyPath("ViewportOrigin")); moveStoryboard.Children.Add(moveAnimation); totalImagesAdded++; } else { break; } } } if (!_msi.Resources.Contains("myAnim")) { _msi.Resources.Add("myAnim", moveStoryboard); } this._msi.ViewportOrigin = new Point(-margin, -margin); this._msi.ViewportWidth = totalWidth + margin; // Play Storyboard moveStoryboard.Begin(); } else { MultiScaleSubImage currentImage = _randomList[0]; currentImage.ViewportWidth = 1 + 2 * margin; currentImage.ViewportOrigin = new Point(0, 0); this._msi.ViewportOrigin = new Point(-margin, -margin); this._msi.ViewportWidth = 1; } } private List<MultiScaleSubImage> RandomizedListOfImages() { List<MultiScaleSubImage> imageList = new List<MultiScaleSubImage>(); Random ranNum = new Random(); // Store List of Images foreach (MultiScaleSubImage subImage in _msi.SubImages) { subImage.Opacity = 1; imageList.Add(subImage); } int numImages = imageList.Count; // Randomize Image List for (int a = 0; a < numImages; a++) { MultiScaleSubImage tempImage = imageList[a]; imageList.RemoveAt(a); int ranNumSelect = ranNum.Next(imageList.Count); imageList.Insert(ranNumSelect, tempImage); } return imageList; } } }
A common used feature in Deep Zoom Images is the “Home” Feature. If you zoom deep into an image you might get lost
. But don’t be afraid. The following behavior applied to you MultiScaleImage bring you back to the origin position (Home) of your image.
XAML-Code
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" x:Class="DeepZoomMouseBehavior.MainPage" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock Text="Deep Zoom Sample" /> <MultiScaleImage x:Name="_msi" Source="Images/dzc_output.xml" Margin="0,19,0,0"> <i:Interaction.Behaviors> <TheOliver_Controls:DeepZoomBehavior /> </i:Interaction.Behaviors> </MultiScaleImage> <Button HorizontalAlignment="Right" VerticalAlignment="Top" Width="53" Content="Home"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:DeepZoomNavigateHomeBehavior TargetName="_msi" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> </Grid> </UserControl>
Sourcecode for Behavior
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows.Interactivity; using System.Windows; using System.Windows.Controls; namespace TheOliver.Controls { public class DeepZoomNavigateHomeBehavior : TargetedTriggerAction<MultiScaleImage> { MultiScaleImage msi; protected override void Invoke(object parameter) { msi = this.Target as MultiScaleImage; msi.ViewportWidth = 1; msi.ViewportOrigin = new Point(0, 0); } } }
Deep Zoom is brilliant, awesome, super exciting … I LOVE DEEP ZOOM. And I love to create my own applications based on Deep Zoom. In Silverlight you can use Deep Zoom with the MultiScaleImage-Control. The challenge is, it doesn’t bring support for navigation in a deep zoom image. So you have to do it by yourself … or better use a Behavior for this features.
XAML-Code
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" x:Class="DeepZoomMouseBehavior.MainPage" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock Text="Deep Zoom Sample" /> <MultiScaleImage x:Name="_msi" Source="Images/dzc_output.xml" Margin="0,12,0,0"> <i:Interaction.Behaviors> <TheOliver_Controls:DeepZoomBehavior /> </i:Interaction.Behaviors> </MultiScaleImage> </Grid> </UserControl>
Sourcecode
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interactivity; namespace TheOliver.Controls { public class DeepZoomBehavior : Behavior<MultiScaleImage> { MultiScaleImage _msi; Point _lastMousePos = new Point(); double _zoom = 1; bool _mouseButtonPressed = false; bool _mouseIsDragging = false; Point _dragOffset; Point _currentPosition; private double ZoomFactor { get { return _zoom; } set { _zoom = value; } } protected override void OnAttached() { _msi = this.AssociatedObject; _msi.MouseMove += delegate(object sender, MouseEventArgs e) { if (_mouseButtonPressed) { _mouseIsDragging = true; } _lastMousePos = e.GetPosition(_msi); }; _msi.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) { _mouseButtonPressed = true; _mouseIsDragging = false; _dragOffset = e.GetPosition(_msi); _currentPosition = _msi.ViewportOrigin; }; _msi.MouseLeave += delegate(object sender, MouseEventArgs e) { _mouseIsDragging = false; }; _msi.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e) { _mouseButtonPressed = false; if (_mouseIsDragging == false) { bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; ZoomFactor = 2.0; if (shiftDown) ZoomFactor = 0.5; Zoom(ZoomFactor, _lastMousePos); } _mouseIsDragging = false; }; _msi.MouseMove += delegate(object sender, MouseEventArgs e) { if (_mouseIsDragging) { Point newOrigin = new Point(); newOrigin.X = _currentPosition.X - (((e.GetPosition(_msi).X - _dragOffset.X) / _msi.ActualWidth) * _msi.ViewportWidth); newOrigin.Y = _currentPosition.Y - (((e.GetPosition(_msi).Y - _dragOffset.Y) / _msi.ActualHeight) * _msi.ViewportWidth); _msi.ViewportOrigin = newOrigin; } }; _msi.MouseWheel += (s,e) => { e.Handled = true; if (e.Delta > 0) { ZoomFactor = 1.2; } else { ZoomFactor = .80; } Zoom(ZoomFactor, _lastMousePos); }; } public void Zoom(double zoom, Point pointToZoom) { Point logicalPoint = _msi.ElementToLogicalPoint(pointToZoom); _msi.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y); } } }
Last week I started my daily demo challenge. The Result, five simple, and easy to use samples for Silverlight.
15.03.2010 – Silverlight 3: Text Tipping Control // [Preview]
16.03.2010 – Silverlight 3: Image Spindle // [Preview]
17.03.2010 – Silverlight 3: Image Stack // [Preview]
18.03.2010 – Silverlight 3: Behavior – 3D Hover Effect // [Preview]
19.03.2010 – Silverlight 3: Trigger Action – Fullscreen // [Preview]
If you have any suggestions and comments, please feel free to comment.
Best regards,
The-Oliver
A common needed and used feature in Silverlight is the Fullscreen Mode. A feature to switch the current application from a hosted in browser to fullscreen mode. This features is interesting in scenarios like Point of Sales- or Games-Applications.
Normal Browser Mode
Full Screen Mode
XAML-Code
<UserControl x:Class="FullScreenBehavior.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <TheOliver_Controls:FullScreenAction/> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Rectangle Stroke="Black" Margin="155,113,141,110"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonUp"> <TheOliver_Controls:FullScreenAction/> </i:EventTrigger> </i:Interaction.Triggers> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> </Grid> </UserControl>
Sourcecode
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.Windows; using System.Windows.Interactivity; namespace TheOliver.Controls { public class FullScreenAction : TargetedTriggerAction<FrameworkElement> { protected override void Invoke(object o) { Application.Current.Host.Content.IsFullScreen = !Application.Current.Host.Content.IsFullScreen; } } }
Behaviors are great new feature in Silverlight 3 (or better in Blend 3) for adding “features” to a control without coding. My favorite sample is a hover effect, that applies when a mouse enters a control.
XAML-Code:
<UserControl x:Class="Hover3DBehavior.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls" d:DesignHeight="300" d:DesignWidth="400" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"> <Grid x:Name="LayoutRoot" Background="White"> <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="89,78,0,0" Name="button1" VerticalAlignment="Top" Width="75"> <i:Interaction.Behaviors> <TheOliver_Controls:Hover3DBehavior /> </i:Interaction.Behaviors> </Button> <dataInput:Label Height="50" HorizontalAlignment="Left" Margin="274,64,0,0" Name="label1" VerticalAlignment="Top" Width="100" Content="Hello World"> <i:Interaction.Behaviors> <TheOliver_Controls:Hover3DBehavior /> </i:Interaction.Behaviors> </dataInput:Label> <RadioButton Content="RadioButton" Height="16" HorizontalAlignment="Left" Margin="12,133,0,0" Name="radioButton1" VerticalAlignment="Top"> <i:Interaction.Behaviors> <TheOliver_Controls:Hover3DBehavior /> </i:Interaction.Behaviors> </RadioButton> </Grid> </UserControl>
Source-Code:
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System.ComponentModel; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; using System.Windows.Media; using System.Windows.Media.Animation; namespace TheOliver.Controls { public class Hover3DBehavior : Behavior<UIElement> { PlaneProjection _planeProjection; public Hover3DBehavior() : base() { } Storyboard _hoverMe; Storyboard _unhoverMe; public double ZHoverValue { get { return (double)GetValue(ZHoverValueProperty); } set { SetValue(ZHoverValueProperty, value); } } public static readonly DependencyProperty ZHoverValueProperty = DependencyProperty.Register("ZHoverValue", typeof(double), typeof(Hover3DBehavior), new PropertyMetadata(500.0, null)); public int HoverDurationMilliseconds { get { return (int)GetValue(HoverDurationMillisecondsProperty); } set { SetValue(HoverDurationMillisecondsProperty, value); } } public static readonly DependencyProperty HoverDurationMillisecondsProperty = DependencyProperty.Register("HoverDurationMilliseconds" , typeof(int) , typeof(Hover3DBehavior), new PropertyMetadata(200, null)); #region Overrides protected override void OnAttached() { base.OnAttached(); _planeProjection = new PlaneProjection(); this.AssociatedObject.Projection = _planeProjection; if (!DesignerProperties.GetIsInDesignMode(this)) { _hoverMe = new Storyboard(); DoubleAnimation da1 = new DoubleAnimation(); _hoverMe.Children.Add(da1); da1.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, HoverDurationMilliseconds)); da1.To = this.ZHoverValue; Storyboard.SetTarget(da1, this.AssociatedObject); Storyboard.SetTargetProperty(da1, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)")); DoubleAnimation da2 = new DoubleAnimation(); BounceEase be2 = new BounceEase(); be2.EasingMode = EasingMode.EaseOut; be2.Bounces = 3; da2.EasingFunction = be2; _unhoverMe = new Storyboard(); _unhoverMe.Children.Add(da2); da2.Duration = new Duration(new System.TimeSpan(0, 0, 0, 0, 1000)); da2.To = 0.0; Storyboard.SetTarget(da2, this.AssociatedObject); Storyboard.SetTargetProperty(da2, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)")); if ((this.AssociatedObject as FrameworkElement).Resources.Contains("hoverme")) { (this.AssociatedObject as FrameworkElement).Resources.Remove("hoverme"); } (this.AssociatedObject as FrameworkElement).Resources.Add("hoverme", _hoverMe); if ((this.AssociatedObject as FrameworkElement).Resources.Contains("unhoverme")) { (this.AssociatedObject as FrameworkElement).Resources.Remove("unhoverme"); } (this.AssociatedObject as FrameworkElement).Resources.Add("unhoverme", _unhoverMe); } this.AssociatedObject.MouseEnter += AssociatedObject_MouseEnter; this.AssociatedObject.MouseLeave += AssociatedObject_MouseLeave; } protected override void OnDetaching() { base.OnDetaching(); this.AssociatedObject.Projection = null; _planeProjection = null; this.AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter; this.AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave; } #endregion #region Events void AssociatedObject_MouseLeave(object sender, MouseEventArgs e) { _unhoverMe.Begin(); } void AssociatedObject_MouseEnter(object sender, MouseEventArgs e) { //FrameworkElement e1 = this.AssociatedObject as FrameworkElement; //if (e1.Parent is Panel) //{ // Panel p = e1.Parent as Panel; // if (p != null) // { // UIElement element = this.AssociatedObject; // element.SetValue(UIElement. // p.Children.Remove(element); // p.Children.Add(element); // } //} _hoverMe.Begin(); } #endregion } }
An interesting control is a Image Stack, where Images are stacked on top of each other. Normally you remove the image on top and put it to the back. So I did. If you double-click the stack an animation move the image to the back.
XAML-Code:
<UserControl x:Class="ImageStack.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="321" d:DesignWidth="416" xmlns:my="clr-namespace:TheOliver.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <my:ImageStack Margin="12" x:Name="imageStack1" Background="Gray" > <Image Source="/ImageStack;Component/Assets/1.jpg" /> <Image Source="/ImageStack;Component/Assets/2.jpg" /> <Image Source="/ImageStack;Component/Assets/3.jpg" /> <Image Source="/ImageStack;Component/Assets/4.jpg" /> <Image Source="/ImageStack;Component/Assets/5.jpg" /> </my:ImageStack> </Grid> </UserControl>
Source-Code:
// Copyright © Microsoft Corporation. All Rights Reserved. // This code released under the terms of the // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) using System; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Effects; using System.Windows.Threading; namespace TheOliver.Controls { public class ImageStack : Panel { public ImageStack() { _doubleClickTimer = new DispatcherTimer(); _doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, DoubleClickSpeedInMS); _doubleClickTimer.Tick += (s, e) => { _clickCount = 0; _doubleClickTimer.Stop(); }; this.MouseLeftButtonUp += (s, e) => { if (_clickCount == 1) { // Doubleclick detected HideCurrentImage(); } else { _clickCount++; _doubleClickTimer.Start(); } }; _hideStoryboard.Completed += (s, e) => { this.Children.Remove(_removedImage); this.Children.Insert(0, _removedImage); ShowNextImage(); }; _showStoryboard.Completed += (s, e) => { _storyboardIsActive = false; }; } Random _random = new Random(); int _clickCount; DispatcherTimer _doubleClickTimer; Storyboard _hideStoryboard = new Storyboard(); Storyboard _showStoryboard = new Storyboard(); Image _removedImage; bool _storyboardIsActive = false; double _newX; double _newY; Size _finalSize; private void ShowNextImage() { TimeSpan duration = new TimeSpan(0, 0, 0, 0, AnimationInMS); // Part 2 DoubleAnimation xa2 = new DoubleAnimation(); xa2.Duration = duration; xa2.To = -_newX; DoubleAnimation ya2 = new DoubleAnimation(); ya2.Duration = duration; ya2.To = -_newY; _showStoryboard.Stop(); _showStoryboard.Children.Clear(); _showStoryboard.Duration = duration; _showStoryboard.Children.Add(xa2); _showStoryboard.Children.Add(ya2); TransformGroup tg = _removedImage.RenderTransform as TransformGroup; TranslateTransform tt2 = new TranslateTransform(); tg.Children.Add(tt2); _removedImage.RenderTransform = tg; Storyboard.SetTarget(xa2, tt2); //set Animation Target Storyboard.SetTargetProperty(xa2, new PropertyPath("X")); // set Animation TargetProperty Storyboard.SetTarget(ya2, tt2); Storyboard.SetTargetProperty(ya2, new PropertyPath("Y")); if (this.Resources.Contains("showme")) { this.Resources.Remove("showme"); } this.Resources.Add("showme", _showStoryboard); _showStoryboard.Begin(); } bool _layouted = false; protected override Size ArrangeOverride(Size finalSize) { _finalSize = finalSize; if (!_layouted) { LayoutImages(_finalSize); _layouted = true; } return base.ArrangeOverride(finalSize); } private void HideCurrentImage() { if (_storyboardIsActive) { return; } _storyboardIsActive = true; _removedImage = this.Children[this.Children.Count - 1] as Image; if (_removedImage != null) { TimeSpan duration = new TimeSpan(0, 0, 0, 0, AnimationInMS); double angle = _random.Next(360); _newX = Math.Sin(angle) * this.RenderSize.Width; _newY = Math.Cos(angle) * this.RenderSize.Height; _hideStoryboard.Stop(); _hideStoryboard.Children.Clear(); // Part 1 DoubleAnimation xa1 = new DoubleAnimation(); xa1.Duration = duration; xa1.To = _newX; DoubleAnimation ya1 = new DoubleAnimation(); ya1.Duration = duration; ya1.To = _newY; _hideStoryboard.Duration = duration; _hideStoryboard.Children.Add(xa1); _hideStoryboard.Children.Add(ya1); TransformGroup tg = _removedImage.RenderTransform as TransformGroup; TranslateTransform tt = new TranslateTransform(); tg.Children.Add(tt); _removedImage.RenderTransform = tg; Storyboard.SetTarget(xa1, tt); Storyboard.SetTargetProperty(xa1, new PropertyPath("X")); Storyboard.SetTarget(ya1, tt); Storyboard.SetTargetProperty(ya1, new PropertyPath("Y")); if (this.Resources.Contains("hideme")) { this.Resources.Remove("hideme"); } this.Resources.Add("hideme", _hideStoryboard); _hideStoryboard.Begin(); } } private Size LayoutImages(Size finalSize) { var images = this.Children.OfType<Image>(); Random rnd = new Random(); foreach (var image in images) { // Drop Shadow Effect if (ShowDropShadowEffect) { DropShadowEffect dse = new DropShadowEffect(); dse.ShadowDepth = 0.3; image.Effect = dse; } // Center image image.VerticalAlignment = System.Windows.VerticalAlignment.Center; image.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; TransformGroup tg = new TransformGroup(); // Scale to fit the finalsize * 90% image.Stretch = Stretch.Uniform; image.Width = finalSize.Width * ResizeFactor; image.Height = finalSize.Height * ResizeFactor; image.Margin = new Thickness( (finalSize.Width - image.Width) / 2, (finalSize.Height - image.Height) / 2, (finalSize.Width - image.Width) / 2, (finalSize.Height - image.Height) / 2); // Rotate image RotateTransform rt = new RotateTransform(); rt.Angle = 90 - rnd.Next(180); rt.CenterX = image.Width / 2; rt.CenterY = image.Height / 2; tg.Children.Add(rt); image.RenderTransform = tg; } return finalSize; } #region Properties public double ResizeFactor { get { return (double)GetValue(ResizeFactorProperty); } set { SetValue(ResizeFactorProperty, value); } } public static readonly DependencyProperty ResizeFactorProperty = DependencyProperty.Register( "ResizeFactor", typeof(double), typeof(ImageStack), new PropertyMetadata(0.5, OnValueChanged)); private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ImageStack stack = sender as ImageStack; stack.InvalidateArrange(); } public bool ShowDropShadowEffect { get { return (bool)GetValue(ShowDropShadowEffectProperty); } set { SetValue(ShowDropShadowEffectProperty, value); } } public static readonly DependencyProperty ShowDropShadowEffectProperty = DependencyProperty.Register( "ShowDropShadowEffect", typeof(bool), typeof(ImageStack), new PropertyMetadata(true, OnValueChanged)); public int DoubleClickSpeedInMS { get { return (int)GetValue(DoubleClickSpeedInMSProperty); } set { SetValue(DoubleClickSpeedInMSProperty, value); } } public static readonly DependencyProperty DoubleClickSpeedInMSProperty = DependencyProperty.Register( "DoubleClickSpeedInMS", typeof(int), typeof(ImageStack), new PropertyMetadata(500, OnDoubleClickSpeedChanged)); private static void OnDoubleClickSpeedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ImageStack stack = sender as ImageStack; stack._doubleClickTimer.Stop(); stack._doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, (int)e.NewValue); } public bool EnableDragging { get { return (bool)GetValue(EnableDraggingProperty); } set { SetValue(EnableDraggingProperty, value); } } public static readonly DependencyProperty EnableDraggingProperty = DependencyProperty.Register( "EnableDragging", typeof(bool), typeof(ImageStack), new PropertyMetadata(false)); public int AnimationInMS { get { return (int)GetValue(AnimationInMSProperty); } set { SetValue(AnimationInMSProperty, value); } } public static readonly DependencyProperty AnimationInMSProperty = DependencyProperty.Register( "AnimationInMS", typeof(int), typeof(ImageStack), new PropertyMetadata(125)); #endregion } } Download Sourcecode
There are a lot of carousel controls out there, but I didn’t find any control which can be customized easy without re-coding or “hacking” hard-coded links to images. What I want is a control that can be customized from the design-interface or in XAML, but not in code.
So I created based on a sample on the web a really reusable carousel with mouse control to move it to the left or right.
And … very important you can insert as much pictures as you want, and change different other parameters like radius
A spindle with five images ….
A spindle with ten images … and no code change.
Xaml-Code:
<UserControl x:Class="ImageSpindle.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:my="clr-namespace:TheOliver.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <my:ImageSpindle Margin="12" x:Name="imageSpindle1"> <Image Source="Assets/1.jpg" /> <Image Source="Assets/2.jpg" /> <Image Source="Assets/3.jpg" /> <Image Source="Assets/4.jpg" /> <Image Source="Assets/5.jpg" /> </my:ImageSpindle> </Grid> </UserControl>
Control-Sourcecode:
using System; using System.ComponentModel; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace TheOliver.Controls { public class ImageSpindle : Panel { Point _mousePoint; double _height; double _width; bool _isMouseOver; public ImageSpindle() { this.Loaded += (s, e) => { if (DesignerProperties.GetIsInDesignMode(this)) { return; } this.MouseMove += (s1, e1) => { _mousePoint = e1.GetPosition(this); }; CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); }; this.MouseEnter += (s, e) => { _isMouseOver = true; }; this.MouseLeave += (s, e) => { _isMouseOver = false; }; } protected override Size MeasureOverride(Size availableSize) { _height = availableSize.Height; _width = availableSize.Width; var images = this.Children.OfType<Image>(); int imageCount = images.Count(); if (imageCount > 0) { double step = 360.0 / imageCount; double currentStep = 0; foreach (var image in images) { UpdateImage(image, currentStep); currentStep += step; } } return base.MeasureOverride(availableSize); } private Image UpdateImage(Image image, double step) { image.Height = ImageHeight; image.Width = ImageWidth; image.Margin = new Thickness( (_width - ImageWidth) / 2, (_height - ImageHeight) / 2, (_width - ImageWidth) / 2, (_height - ImageHeight) / 2); image.RenderTransformOrigin = new Point(0.5, 0.5); image.Stretch = ImageStretch; PlaneProjection pp = new PlaneProjection(); pp.CenterOfRotationZ = SpindleCenterOfRotation; pp.RotationY = step; image.Projection = pp; return image; } void CompositionTarget_Rendering(object sender, EventArgs e) { if (StopWhenMouseLeft) { if (!_isMouseOver) { return; } } if (double.IsNaN(_width) || _width == 0) { return; } foreach (var image in this.Children.OfType<Image>()) { PlaneProjection pp = image.Projection as PlaneProjection; if (pp != null) { pp.RotationY += ((_mousePoint.X - (_width / 2)) / _width) * 10; } image.Opacity = (_mousePoint.Y / _height) * 0.5 + 0.5; } } #region Properties public Stretch ImageStretch { get { return (Stretch)GetValue(ImageStretchProperty); } set { SetValue(ImageStretchProperty, value); } } public static readonly DependencyProperty ImageStretchProperty = DependencyProperty.Register( "ImageStretch", typeof(Stretch), typeof(ImageSpindle), new PropertyMetadata(Stretch.Uniform, OnValueChanged)); public double ImageWidth { get { return (double)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } public static readonly DependencyProperty ImageWidthProperty = DependencyProperty.Register( "ImageWidth", typeof(double), typeof(ImageSpindle), new PropertyMetadata(160.0, OnValueChanged)); public double ImageHeight { get { return (double)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } public static readonly DependencyProperty ImageHeightProperty = DependencyProperty.Register( "ImageHeight", typeof(double), typeof(ImageSpindle), new PropertyMetadata(120.0, OnValueChanged)); public double SpindleCenterOfRotation { get { return (double)GetValue(SpindleCenterOfRotationProperty); } set { SetValue(SpindleCenterOfRotationProperty, value); } } public static readonly DependencyProperty SpindleCenterOfRotationProperty = DependencyProperty.Register( "SpindleCenterOfRotation", typeof(double), typeof(ImageSpindle), new PropertyMetadata(-160.0, OnValueChanged)); private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ImageSpindle spindle = sender as ImageSpindle; spindle.InvalidateMeasure(); } public bool StopWhenMouseLeft { get { return (bool)GetValue(StopWhenMouseLeftProperty); } set { SetValue(StopWhenMouseLeftProperty, value); } } public static readonly DependencyProperty StopWhenMouseLeftProperty = DependencyProperty.Register( "StopWhenMouseLeft", typeof(bool), typeof(ImageSpindle), new PropertyMetadata(true)); #endregion } }
Based on a true story, I built a small control for Silverlight to tip text, like an old fashioned typewriter.
Liveversion: here.
Code for the Control:
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; namespace TheOliver.Controls { public class TippingText : UserControl { TextBox _textblock; DispatcherTimer _timer; public TippingText() { _textblock = new TextBox(); this.Content = _textblock; _timer = new DispatcherTimer(); _timer.Interval = new TimeSpan(0, 0, 0, 0, TippingSpeedInMilliseconds); _timer.Tick += (s, e) => { ShowNextCharacter(); _currentCharacter++; if (_currentCharacter >= Text.Length) { _timer.Stop(); if (Repeat) { _currentCharacter = 0; _timer.Start(); } } }; this.Loaded += (s, e) => { if (Text.Length > 0) { _timer.Start(); } }; } private void ShowNextCharacter() { if (Text.Length > _currentCharacter + 1) { _textblock.Text = Text.Substring(0, _currentCharacter + 1); } } private int _currentCharacter; public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof(string), typeof(TippingText), new PropertyMetadata("No Text", OnValueChanged)); private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args) { TippingText tt = sender as TippingText; tt._timer.Stop(); tt._timer.Interval = new TimeSpan(0, 0, 0, 0, tt.TippingSpeedInMilliseconds); tt._currentCharacter = 0; tt._textblock.TextWrapping = tt.TextWrapping; tt._textblock.TextAlignment = tt.TextAlignment; tt._textblock.Text = tt.Text; if (tt.Text.Length > 0) { tt._timer.Start(); } } public int TippingSpeedInMilliseconds { get { return (int)GetValue(TippingSpeedInMillisecondsProperty); } set { SetValue(TippingSpeedInMillisecondsProperty, value); } } public static readonly DependencyProperty TippingSpeedInMillisecondsProperty = DependencyProperty.Register( "TippingSpeedInMilliseconds", typeof(int), typeof(TippingText), new PropertyMetadata(200, OnValueChanged)); public bool Repeat { get { return (bool)GetValue(RepeatProperty); } set { SetValue(RepeatProperty, value); } } public static readonly DependencyProperty RepeatProperty = DependencyProperty.Register( "Repeat", typeof(bool), typeof(TippingText), new PropertyMetadata(true, OnValueChanged)); public TextWrapping TextWrapping { get { return (TextWrapping)GetValue(TextWrappingProperty); } set { SetValue(TextWrappingProperty, value); } } public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register( "TextWrapping", typeof(TextWrapping), typeof(TippingText), new PropertyMetadata(TextWrapping.Wrap, OnValueChanged)); public TextAlignment TextAlignment { get { return (TextAlignment)GetValue(TextAlignmentProperty); } set { SetValue(TextAlignmentProperty, value); } } public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register( "TextAlignment", typeof(TextAlignment), typeof(TippingText), new PropertyMetadata(TextAlignment.Center, OnValueChanged)); } }
Oft fragt man sich, wie man in Expression Blend einfach mal eine Funktion in seine Anwendung integrieren kann, ohne dafür extra Code schreiben zu müssen.
Ein solcher Fall ist z.B. der Wechsel in den Vollbildmodus und wieder zurück. Mit dem folgenden Trigger “FullScreenAction” kann man so etwas ohne Code in Blend durchführen.
Vorrausgesetzt, man hat die Klasse unten in seinem Projekt integriert oder referenziert.
using System.Windows;
using System.Windows.Interactivity;
namespace Oliver.Controls.Behaviors
{
public class FullScreenAction
: TargetedTriggerAction<FrameworkElement>
{
protected override void Invoke(object o)
{
Application.Current.Host.Content.IsFullScreen =
!Application.Current.Host.Content.IsFullScreen;
}
}
}
Eines der neuen Features von Silverlight 3 und Expression Blend 3 sind die Behaviors. Mit diesen Behaviors lassen sich sehr einfach “generische” Funktionalität erstellen, die man dann auf andere Objekte übertragen kann.
Das folgende Beispiel, soll mit Hilfe des Mausrades, Objekte vergrößern und verkleinern. Geht man mit der Maus auf ein bestimmtes Objekt und dreht dann am Mausrad, dann wird dieses Objekt größer oder kleiner. Verläßt die Maus den Fokus, dann wird das Objekt wieder auf Normalgröße gesetzt.
Vorher:
Nachher:
Damit man das ganze in Blend einfach verwenden kann, muss die unten beschriebene Klasse im aktuellen Projekt integriert oder referenziert sein.
Code für die Behavior-Klasse:
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Oliver.Behaviors
{
public class MouseMagnifier : Behavior<FrameworkElement>
{
FrameworkElement _target;
ScaleTransform _scale;
private double _scaleFactor = 0.2;
public double ScaleFactor
{
get { return _scaleFactor; }
set { _scaleFactor = value; }
}
protected override void OnAttached()
{
_target = this.AssociatedObject;
_target.MouseWheel += new MouseWheelEventHandler(_target_MouseWheel);
_target.MouseLeave += new MouseEventHandler(_target_MouseLeave);
_scale = new ScaleTransform();
_target.RenderTransform = _scale;
base.OnAttached();
}
void _target_MouseLeave(object sender, MouseEventArgs e)
{
_scale.ScaleX = 1;
_scale.ScaleY = 1;
}
void _target_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
_scale.ScaleX += _scaleFactor;
_scale.ScaleY += _scaleFactor;
}
else
{
_scale.ScaleX -= _scaleFactor;
_scale.ScaleY -= _scaleFactor;
}
}
}
}
XAML-Code für die UI:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:Oliver_Behaviors="clr-namespace:Oliver.Behaviors;assembly=Oliver.Controls.Silverlight.Behaviors" x:Class="Oliver.Apps.ControlTester.Samples.MouseMagnifierBehaviorSample"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle Stroke="Black" Height="66" HorizontalAlignment="Left" Margin="29,56,0,0" VerticalAlignment="Top" Width="126">
<i:Interaction.Behaviors>
<Oliver_Behaviors:MouseMagnifier/>
</i:Interaction.Behaviors>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Button Height="54" HorizontalAlignment="Right" Margin="0,56,69,0" VerticalAlignment="Top" Width="99" Content="Button">
<i:Interaction.Behaviors>
<Oliver_Behaviors:MouseMagnifier/>
</i:Interaction.Behaviors>
</Button>
<TextBox Height="29" Margin="179,0,95,106" VerticalAlignment="Bottom" Text="TextBox" TextWrapping="Wrap">
<i:Interaction.Behaviors>
<Oliver_Behaviors:MouseMagnifier/>
</i:Interaction.Behaviors>
</TextBox>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Text="Use Mousewheel over Controls to resize them. " TextWrapping="Wrap"/>
</Grid>
</UserControl>
Ich hab mal wieder ein neues Steuerelement (inkl. Design-Time-Experience) erstellt.
Mehr Infos und den Download dazu gibt es hier.
In Expression Blend und diversen anderen Anwendungen, findet man immer wieder Hintergründe die nach einer Art Schachmuster aufgebaut sind.
Ich persönlich finde, das dies sehr nett anzusehen ist. Allerdings frag ich ich dann auch immer, wie haben die das gemacht, und vor allem wie kann ich das in meiner eigenen Anwendung übernehmen.
Dazu habe ich dann mal ein eigenes Steuerelement entwickelt, das bereits in der Entwicklungsumgebung zeigt, wie es später aussehen wird. Man kann dieses über typische Eigenschaften, wie Foreground, Background, Gap (Zwischenraum zwischen Rechtecken), RectWidth (Breite eines Vierecks) und RectHeight (Höhe eines Vierecks) anzeigen.
Anbei einige Ausprägungen des fertigen Steuerelementes (RectangleArea).
Der Code für dieses Steuerelement ist recht einfach:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
namespace Oliver.Controls
{
public class RectangleArea : UserControl
{
#region Dependency properties
public static readonly DependencyProperty GapProperty =
DependencyProperty.Register(
"Gap",
typeof(double),
typeof(RectangleArea),
new PropertyMetadata(5d, OnValueChanged));
public double Gap
{
get { return (double)GetValue(GapProperty); }
set { SetValue(GapProperty, value); }
}
public static readonly DependencyProperty RectWidthProperty =
DependencyProperty.Register(
"RectWidth",
typeof(double),
typeof(RectangleArea),
new PropertyMetadata(5d, OnValueChanged));
public double RectWidth
{
get { return (double)GetValue(RectWidthProperty); }
set { SetValue(RectWidthProperty, value); }
}
public static readonly DependencyProperty RectHeightProperty =
DependencyProperty.Register(
"RectHeight",
typeof(double),
typeof(RectangleArea),
new PropertyMetadata(5d, OnValueChanged));
public double RectHeight
{
get { return (double)GetValue(RectHeightProperty); }
set { SetValue(RectHeightProperty, value); }
}
#endregion
#region Internal
private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
RectangleArea panel = (RectangleArea)sender;
panel.UpdateLayout();
}
protected override Size MeasureOverride(Size availableSize)
{
DrawContent(availableSize.Width, availableSize.Height);
return base.MeasureOverride(availableSize);
}
private void DrawContent(double width, double height)
{
Canvas canvas = new Canvas();
canvas.Background = this.Background;
RectWidth = RectWidth == 0 ? 1 : RectWidth;
RectHeight = RectHeight == 0 ? 1 : RectHeight;
double xd = width / (RectWidth + Gap);
double yd = height / (RectHeight + Gap);
for (int x = 0; x < xd; x++)
{
bool alternatingX = x % 2 == 0;
for (int y = 0; y < yd; y++)
{
bool alternatingY = y % 2 == 0;
Rectangle r = new Rectangle();
if ((alternatingX & !alternatingY) ||
(!alternatingX & alternatingY))
{
continue;
}
double left = x * (RectWidth + Gap);
double top = y * (RectHeight + Gap);
r.SetValue(Canvas.LeftProperty, left);
r.SetValue(Canvas.TopProperty, top);
r.Width = RectWidth;
r.Height = RectHeight;
r.Fill = this.Foreground;
canvas.Children.Add(r);
}
}
this.Content = canvas;
}
#endregion
}
}
Das Anordnen der Elemente geschieht in der Methode DrawContent. Diese wird jedesmal aufgerufen, wenn sich ein Wert ändert.
Windows 7 wird richtig, richtig, richtig gut. Zeigt wie gut ihr Anwendungen entwickeln könnt und gewinnt Schotter, Kies, Cash, Money, Piepen, Moneten, Kohle, Asche, Moss und Zaster.
Link: https://www.code7contest.com/
Ich darf leider nicht teilnehmen.