Archive of posts filed under the WPF category.

WPF and Cursor

I was trying to figure out today the WPF’s equivalent to old WinForms functionality that allows a developer to change cursor shape.  For example, if you have a control that may take a second or two to load, you want to change cursor shape to hourglass (WaitCursor), then change it back once control has been loaded.

Turns out, this is just as easy in WPF, just not as intuitive.

Mouse.OverrideCursor = Cursors.Wait;

To change it back to default:

Mouse.OverrideCursor = null;

You will need to import a namespace:

using System.Windows.Input;

WPF ListBox and SelectedItem’s BackColor

In our application we use black as background color everywhere and white or light gray as foreground color.  I was working on a ListBox that has very complicated item’s layout.  Essentially there are about 8 different controls contained within each item.  ListBox is simply used as a container to view the data, we really do not need to know which item is highlighted by the user.  Default background color for ListBox’s highlighted item is a system color, called HighlightBrushKey.  In my case (on my machine) it is blue.  Highlighted items looks UGLY with this color schema.  So, I wanted to simply remove the highlight altogether.  To do so, I defined a custom style as so

<UserControl.Resources>

    <Style x:Key="customListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent"/>
        </Style.Resources>
    </Style>

</UserControl.Resources>

This style is replacing default system color with transparent color, essentially removing the highlights.  To use this style in the ListBox, I did the following:

<ListBox ItemsSource="{Binding Path=ClientProductGroups}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ItemContainerStyle="{StaticResource customListBoxItemStyle}">

Reusable WPF/Silverlight Animations

As I was working on fixing some animations that got broken due to splitting on one control into multiple controls, I came up with an idea of creating a single animation that could be apply to multiple controls.  In my case, the animation was two-fold.  As control came into view, it should fade into the view as well as "bounce".  Essentially, this animation utilizes scale transform and opacity transform.  Here is the new class I wrote.  The cool thing is that this class can be called with any UI element or control.As a matter of fact, the control does not even need to have transform group defined for it, as the class will create one on the fly to support desired animation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;

namespace App.Animation
{
    public static class InitialControlAnimation
    {
        public static void Play(UIElement controlToAnimate)
        {
            Storyboard story = new Storyboard();

            // opacity animation
            DoubleAnimationUsingKeyFrames opacityAnimation = new DoubleAnimationUsingKeyFrames();
            opacityAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.8, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            ((SplineDoubleKeyFrame)opacityAnimation.KeyFrames[2]).KeySpline = new KeySpline(0, 1, 1, 1);
            Storyboard.SetTarget(opacityAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(UIElement.OpacityProperty));
            story.Children.Add(opacityAnimation);

            //stretch horizontally
            DoubleAnimationUsingKeyFrames scaleXAnimation = new DoubleAnimationUsingKeyFrames();
            scaleXAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleXAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
            story.Children.Add(scaleXAnimation);

            //stretch vertically
            DoubleAnimationUsingKeyFrames scaleYAnimation = new DoubleAnimationUsingKeyFrames();
            scaleYAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleYAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
            story.Children.Add(scaleYAnimation);

            if (!(controlToAnimate.RenderTransform is TransformGroup))
            {
                TransformGroup group = new TransformGroup();
                group.Children.Add(new ScaleTransform(1, 1, controlToAnimate.RenderSize.Height / 2, controlToAnimate.RenderSize.Width / 2));
                controlToAnimate.RenderTransform = group;
            }
            story.Begin();

        }
    }
}