Archive

Posts Tagged ‘FAQ’

Coverflow-Control in Silverlight inkl. Sourcecode

October 15th, 2009

Ich war lange auf der Suche nach einem Coverflow-Control, welches wiederverwertbar ist. Leider absolute Fehlanzeige, jedes Control das ich gefunden habe war nett, aber nicht wirklich brauchbar um damit einen Designer einigermaßen Glücklich zu machen.

Was heißt für mich “einen Designer glücklich machen”?

Er will das Control verwenden und was darin anzeigen, er will nicht stundenlang Sourcecode durchforsten und dort händisch die Bilder austauschen. Dafür gibt es doch Komponenten.

Also habe ich mich ran gemacht und so ein Coverflow-Control einfach selber geschrieben.

Feature 1: Design-Time Support

Das Control stellt sich in Blend bereits dar. Man muss nicht die ganze Anwendung erst starten. Damit unterscheidet es sich schon von allen Controls die ich gefunden habe.

image

Feature 2: Das Coverflow wurde von Panel abgeleitet.

Panels haben die schöne Eigenschaft, das sie Children haben können. Und das bedeutet für den Designer, man kann einfach via Drag & Drop Elemente in das Coverflow ziehen und wieder entfernen.

image

Feature 3: Konfigurieren über Eigenschaften

Ist es zu viel verlangt, das ich meine Controls ein individuelles Aussehen geben möchte? Warum bietet man den Blend-Benutzer nicht direkt eine Fülle von Eigenschaften zum Konfigurieren an? Keine Ahnung. Ich tu es :)

image

 

Der Sourcecode ist lediglich 427 Zeilen lang. Für die Beispiele die ich zu Coverflow gefunden habe, ein absoluter Rekord (Eigenlob ist an dieser Stelle mal erlaubt) ;)

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.ComponentModel;

namespace Oliver.Controls
{
    public class Coverflow : Panel
    {
        ContentControl _contentControl;

        public Coverflow()
        {
            #region Trick for Keyevents, Panel is not focusable, but contentcontrol is :)
            _contentControl = new ContentControl();
            _contentControl.IsTabStop = true;
            _contentControl.KeyDown += new KeyEventHandler(Coverflow_KeyDown);
            this.Children.Add(_contentControl);
            _contentControl.Focus();
            #endregion

            this.GotFocus += new RoutedEventHandler(Coverflow_GotFocus);
        }

        void Coverflow_GotFocus(object sender, RoutedEventArgs e)
        {
            _contentControl.Focus();
        }

        void Coverflow_KeyDown(object sender, KeyEventArgs e)
        {
            Debug.WriteLine("Key pressed");
            // Move Back
            if (e.Key == Key.Left)
            {
                if (CurrentItemIndex > 0)
                {
                    CurrentItemIndex–;
                }
            }

            // Move forward
            if (e.Key == Key.Right)
            {
                if (CurrentItemIndex + 1 < this.Children.Count)
                {
                    CurrentItemIndex++;
                }
            }
        }

        #region Properties

        [Category("Oliver.Controls")]
        public double OpacityShift
        {
            get { return (double)GetValue(OpacityShiftProperty); }
            set { SetValue(OpacityShiftProperty, value); }
        }

        // Using a DependencyProperty as the backing store for OpacityShift.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty OpacityShiftProperty =
            DependencyProperty.Register(
                "OpacityShift",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(0.1, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public bool DropShadow
        {
            get { return (bool)GetValue(DropShadowProperty); }
            set { SetValue(DropShadowProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DropShadow.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty DropShadowProperty =
            DependencyProperty.Register(
                "DropShadow",
                typeof(bool),
                typeof(Coverflow),
                new PropertyMetadata(false, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public int SpaceBetweenCovers
        {
            get { return (int)GetValue(SpaceBetweenCoversProperty); }
            set { SetValue(SpaceBetweenCoversProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SpaceBetweenCover.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty SpaceBetweenCoversProperty =
            DependencyProperty.Register(
                "SpaceBetweenCovers",
                typeof(int),
                typeof(Coverflow),
                new PropertyMetadata(65, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public int MoveDuration
        {
            get { return (int)GetValue(MoveDurationProperty); }
            set { SetValue(MoveDurationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MoveDuration.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty MoveDurationProperty =
            DependencyProperty.Register(
                "MoveDuration",
                typeof(int),
                typeof(Coverflow),
                new PropertyMetadata(500, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double ItemWidth
        {
            get { return (double)GetValue(ItemWidthProperty); }
            set { SetValue(ItemWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemWidth.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty ItemWidthProperty =
            DependencyProperty.Register(
                "ItemWidth",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(200.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double ItemHeight
        {
            get { return (double)GetValue(ItemHeightProperty); }
            set { SetValue(ItemHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHeight.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty ItemHeightProperty =
            DependencyProperty.Register(
                "ItemHeight",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(400.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public int CurrentItemIndex
        {
            get { return (int)GetValue(CurrentItemIndexProperty); }
            set { SetValue(CurrentItemIndexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentItemIndex.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty CurrentItemIndexProperty =
            DependencyProperty.Register(
                "CurrentItemIndex",
                typeof(int),
                typeof(Coverflow),
                new PropertyMetadata(0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double XShift
        {
            get { return (double)GetValue(XShiftProperty); }
            set { SetValue(XShiftProperty, value); }
        }

        // Using a DependencyProperty as the backing store for XShift.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty XShiftProperty =
            DependencyProperty.Register(
                "XShift",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(0.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double YShift
        {
            get { return (double)GetValue(YShiftProperty); }
            set { SetValue(YShiftProperty, value); }
        }

        // Using a DependencyProperty as the backing store for YShift.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty YShiftProperty =
            DependencyProperty.Register(
                "YShift",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(0.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double ZShift
        {
            get { return (double)GetValue(ZShiftProperty); }
            set { SetValue(ZShiftProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ZShift.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty ZShiftProperty =
            DependencyProperty.Register(
                "ZShift",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(-50.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double RotationAngle
        {
            get { return (double)GetValue(RotationAngleProperty); }
            set { SetValue(RotationAngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RotationAngle.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty RotationAngleProperty =
            DependencyProperty.Register(
                "RotationAngle",
                typeof(double),
                typeof(Coverflow),
                new PropertyMetadata(50.0, OnPropertyChanged));

        [Category("Oliver.Controls")]
        public double SpaceBetweenCenter
        {
            get { return (double)GetValue(SpaceBetweenCenterProperty); }
            set { SetValue(SpaceBetweenCenterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SpaceBetweenCenter.  This enables animation, styling, binding, etc…
        public static readonly DependencyProperty SpaceBetweenCenterProperty =
            DependencyProperty.Register(
                "SpaceBetweenCenter",
                typeof(double),   
                typeof(Coverflow),
                new PropertyMetadata(10.0, OnPropertyChanged));

        private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((Coverflow)sender).InvalidateArrange();
        }

        #endregion

        protected override Size ArrangeOverride(Size finalSize)
        {
            InsertElements();
            return base.ArrangeOverride(finalSize);
        }

        private void InsertElements()
        {
            foreach (var item in this.Children)
            {
                if (item.Visibility == Visibility.Visible)
                {
                    if (this.DropShadow)
                    {
                        DropShadowEffect dse = new DropShadowEffect();
                        dse.BlurRadius = 5;
                        item.Effect = dse;
                    }
                    else
                    {
                        item.Effect = null;
                    }
                    RenderItem(item);
                    item.MouseLeftButtonDown += libItem_MouseLeftButtonDown;
                }
            }
        }

        private void RenderItem(UIElement item)
        {
            int itemIdx = this.Children.IndexOf(item);
            // Größe
            FrameworkElement fe = item as FrameworkElement;
            fe.Width = this.ItemWidth;
            fe.Height = this.ItemHeight;

            // Center
            double centerX = (double)this.Width / 2 – ItemWidth / 2;
            double centerY = (double)this.Height / 2 – ItemHeight / 2;

            TranslateTransform tt = new TranslateTransform();
            tt.X = centerX;
            tt.Y = centerY;
            item.RenderTransform = tt;

            // Opacity
            double opacity = 1;

            // Angle
            PlaneProjection pp = new PlaneProjection();
            if (itemIdx < this.CurrentItemIndex)
            {
                // Item is Left of center
                pp.RotationY = -this.RotationAngle;
                pp.LocalOffsetX =
                    (XShift + SpaceBetweenCovers) * (itemIdx – this.CurrentItemIndex)
                    – (ItemWidth / 2)
                    – SpaceBetweenCenter
                    – ZShift;
                pp.LocalOffsetZ = (this.CurrentItemIndex – itemIdx) * -ZShift;
                pp.LocalOffsetY = (this.CurrentItemIndex – itemIdx) * -YShift;
                opacity = 1-(this.CurrentItemIndex – itemIdx) * OpacityShift;
            }
            else if (itemIdx > this.CurrentItemIndex)
            {
                // Item is Right of center
                int pos = itemIdx – this.CurrentItemIndex;
                pp.RotationY = this.RotationAngle;
                pp.LocalOffsetX =
                    (XShift + SpaceBetweenCovers) * pos
                    + (ItemWidth / 2)
                    + SpaceBetweenCenter
                    + ZShift;
                pp.LocalOffsetZ = pos * -ZShift;
                pp.LocalOffsetY = pos * -YShift;
                opacity = 1- pos * OpacityShift;
            }
            else
            {
                // Item is Center
                pp.RotationY = 0;
                pp.LocalOffsetX = 0;
                pp.LocalOffsetY = 0;
                opacity = 1;
            }

            if (item.Projection == null)
            {
                item.Projection = new PlaneProjection();
            }

            // Create a duration of x seconds.
            TimeSpan ts = TimeSpan.FromMilliseconds(this.MoveDuration);
            Duration duration = new Duration(ts);

            Storyboard sb = new Storyboard();

            #region Rotation Y

            // Rotation Y
            DoubleAnimation daRotationY = new DoubleAnimation();
            daRotationY.Duration = duration;
            PropertyPath propertyPathRotationY = new PropertyPath("(UIElement.Projection).(PlaneProjection.RotationY)");
            Storyboard.SetTarget(daRotationY, item);
            Storyboard.SetTargetProperty(daRotationY, propertyPathRotationY);
            daRotationY.To = pp.RotationY;
            sb.Children.Add(daRotationY);

            #endregion

            #region Local Offset X

            DoubleAnimation daLocalOffsetX = new DoubleAnimation();
            daLocalOffsetX.Duration = duration;
            PropertyPath propertyPathLocalOffsetX = new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetX)");
            Storyboard.SetTarget(daLocalOffsetX, item);
            Storyboard.SetTargetProperty(daLocalOffsetX, propertyPathLocalOffsetX);
            daLocalOffsetX.To = pp.LocalOffsetX;
            sb.Children.Add(daLocalOffsetX);

            #endregion

            #region Local Offset Z

            DoubleAnimation daLocalOffsetZ = new DoubleAnimation();
            daLocalOffsetZ.Duration = duration;
            PropertyPath propertyPathLocalOffsetZ = new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)");
            Storyboard.SetTarget(daLocalOffsetZ, item);
            Storyboard.SetTargetProperty(daLocalOffsetZ, propertyPathLocalOffsetZ);
            daLocalOffsetZ.To = pp.LocalOffsetZ;
            sb.Children.Add(daLocalOffsetZ);

            #endregion

            #region Local Offset Y

            DoubleAnimation daLocalOffsetY = new DoubleAnimation();
            daLocalOffsetY.Duration = duration;
            PropertyPath propertyPathLocalOffsetY = new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetY)");
            Storyboard.SetTarget(daLocalOffsetY, item);
            Storyboard.SetTargetProperty(daLocalOffsetY, propertyPathLocalOffsetY);
            daLocalOffsetY.To = pp.LocalOffsetY;
            sb.Children.Add(daLocalOffsetY);

            #endregion

            #region Opacity

            DoubleAnimation daOpacity = new DoubleAnimation();
            daOpacity.Duration = duration;
            PropertyPath propertyPathOpacity = new PropertyPath("(UIElement.Opacity)");
            Storyboard.SetTarget(daOpacity, item);
            Storyboard.SetTargetProperty(daOpacity, propertyPathOpacity);
            daOpacity.To = opacity;
            sb.Children.Add(daOpacity);

            #endregion

            // Begin the animation.
            sb.Completed += sb_Completed;
            sb.Begin();
        }

        void sb_Completed(object sender, EventArgs e)
        {
            Storyboard sb = sender as Storyboard;
            sb.Completed -= sb_Completed;
        }

        void libItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            int idx = this.Children.IndexOf(sender as UIElement);
            this.CurrentItemIndex = idx;
            this.InvalidateArrange();
        }
    }
}

 

Das Projekt kann hier herunter geladen werden.

Feedback ist natürlich immer gerne gesehen

Social:
  • Print this article!
  • del.icio.us
  • Facebook
  • Twitter

Silverlight ,

Wechseln in Vollbild-Modus und wieder zurück mit Trigger

October 14th, 2009

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.

image

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;

        }
    }
}

Social:
  • Print this article!
  • del.icio.us
  • Facebook
  • Twitter

Silverlight , ,

Objekte mit dem Mausrad vergrößern und verkleiner

October 14th, 2009

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:

image

Nachher:

image

Damit man das ganze in Blend einfach verwenden kann, muss die unten beschriebene Klasse im aktuellen Projekt integriert oder referenziert sein.

image

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>

Social:
  • Print this article!
  • del.icio.us
  • Facebook
  • Twitter

Silverlight , ,