Tag Archives: wp7dev

Animating item selection in a WP7 application

Another day another occasion to share an implementation detail behind my 2Day todo-list application. In this post I share the code used to animate the selection in a ListBox. Here is what is looks like in the create/edit folder dialog of 2Day:

[mediaplayer src=’/wp-content/uploads/2012/09/Listbox-animation.mp4′ ]

You can grab the source code directly here if you want.

Background

The basic idea is to create another element behind the ListBox which will be animated when the selection changes. The tricky part is to find out the appropriate coordinates of this element to make sure it’s perfectly on top of the element we need to higlight.

XAML

The XAML is not very complicated. Notice I use a particular style on the ListBox to remove its scrolling capability. I have to do that because otherwise if the user perform a drag gesture on the ListBox, it moves its element without moving the overlay I need to add. I use a simple Grid to be able to add the overlay “behind” the ListBox:


    



    
        
    

    
        
            
                
            
        
        
            
                
                    
                
            
        
    

Code

The code is for now in the code-behind of the view (see next paragraph for improvements ideas). I use the ItemContainerGenerator property of the ListBox to retrieve the UI element from the Data element (in this example: an integer).

Then I use the TransformToVisual method to get the location of the visual relative to the parent ListBox. Next step is to animate the position of the item using DoubleAnimations:

public partial class MainPage : PhoneApplicationPage
{
    private readonly Point emptyPoint = new Point();
    private DoubleAnimation animationX;
    private DoubleAnimation animationY;
    private Storyboard storyboard;

    public MainPage()
    {
        InitializeComponent();

        this.listbox.ItemsSource = Enumerable.Range(1, 32);

        this.Loaded += this.OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        this.Loaded -= this.OnLoaded;

        this.listbox.SelectionChanged += this.OnSelectionChanged;

        this.overlayHost.Height = this.listbox.ActualHeight;
        this.overlayHost.Width = this.listbox.ActualWidth;
        this.overlayHost.Margin = this.listbox.Margin;

        this.UpdateHighlightedItem();
    }

    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        this.UpdateHighlightedItem();
    }

    private void UpdateHighlightedItem()
    {
        var element = this.listbox.ItemContainerGenerator.ContainerFromIndex(this.listbox.SelectedIndex) as FrameworkElement;
        if (element != null)
        {
            // compute the location of the selected element
            Point destination = element.TransformToVisual(this.listbox).Transform(this.emptyPoint);
            Point origin = this.iconOverlay.TransformToVisual(this.listbox).Transform(this.emptyPoint);

            var translateTransform = this.iconOverlay.RenderTransform as TranslateTransform;
            if (translateTransform == null)
            {
                translateTransform = new TranslateTransform();
                this.iconOverlay.RenderTransform = translateTransform;

                TimeSpan duration = TimeSpan.FromMilliseconds(150);
                IEasingFunction ease = new QuarticEase { EasingMode = EasingMode.EaseOut };

                this.animationX = new DoubleAnimation { Duration = duration, EasingFunction = ease };
                this.animationY = new DoubleAnimation { Duration = duration, EasingFunction = ease };

                this.storyboard = new Storyboard();
                this.storyboard.Children.Add(this.animationX);
                this.storyboard.Children.Add(this.animationY);
            }
            else
            {
                this.storyboard.Stop();
            }

            Storyboard.SetTarget(this.animationX, translateTransform);
            Storyboard.SetTarget(this.animationY, translateTransform);
            Storyboard.SetTargetProperty(this.animationX, new PropertyPath(TranslateTransform.XProperty));
            Storyboard.SetTargetProperty(this.animationY, new PropertyPath(TranslateTransform.YProperty));

            this.animationX.From = origin.X;
            this.animationY.From = origin.Y;
            this.animationX.To = destination.X;
            this.animationY.To = destination.Y;

            this.storyboard.Begin();
        }
    }
}

Possible improvements

As you have seen, the current code is not easy to reuse. I think all the logic cold be embedded in a reusable component. Either using an attached property (and tweaking the template of the ListBox) or by subclassing the orginal ListBox class. I leave this exercise to the reader 🙂

Conclusion

In this article I shared the technique used in 2Day to animate the item selection. Many improvements are possible on top of this code, but I hope it could help WP developers.

Download the source code here if you want.

Property change notifications when using SQL CE on Windows Phone 7.1

I wanted to share a quick syntax trick I’m using to send property change notifications in a Windows Phone 7.1 application. As you already know, the Mango release of Windows Phone introduce local database storage using SQL Compact Edition and Linq-To-SQL.

In the MSDN documentation Local Database Best Practices for Windows Phone, you can find the following recommendation:

Minimizing Memory Usage

LINQ to SQL change tracking works by maintaining two copies of each object (…)

By default, LINQ to SQL will create the two copies of the object when the objects are materialized. Frequently, however, only a handful of objects in the materialized collection will actually get modified within a specific transaction. In this case, there is no reason to keep a second copy of the object.

The INotifyPropertyChanging interface allows the application to notify the DataContext when it is modifying a property that will ultimately be submitted as an update to the database. The DataContext can use that notification as a trigger to create the copy. This way, only the items that are actually changing need to be duplicated.”

It means that to optimize memory usage, your model class should implement both the INotifyPropertyChanged and INotifyPropertyChanging interface. Memory usage is an important aspect, especially on mobile device ! On the Windows Phone platform the certification requires your app to use less than 90MB of memory.

So you’ll probably end up creating a base class for all your model, maybe something like this EntityBase:

public class EntityBase : INotifyPropertyChanged, INotifyPropertyChanging
{
    public event PropertyChangedEventHandler PropertyChanged;
    public event PropertyChangingEventHandler PropertyChanging;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (propertyName == null)
            throw new ArgumentNullException("propertyName");

        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    protected void RaisePropertyChanging(string propertyName)
    {
        if (propertyName == null)
            throw new ArgumentNullException("propertyName");

        if (this.PropertyChanging != null)
            this.PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
    }
}

And you’ll define a property like the following

public string Title
{
    get
    {
        return this.title;
    }
    set 
    { 
        if(this.title != value)
        {
            this.RaisePropertyChanging("Title");
            this.title = value;
            this.RaisePropertyChanged("Title");
        }
    }
}

Because I’m not a big fan of this syntax (property name is duplicated, and it’s easy to use either the first call or the second one…), I tried to find another solution. Here is my proposal

public string Title
{
    get
    {
        return this.title;
    }
    set 
    { 
        if(this.title != value)
        {
            using (this.NotifyChange("Title"))
            {
                this.title = value;
            }
        }
    }
}

This syntax is based on the using operator and the IDisposable interface. The IDisposable interface used to be implemented by objects which must explicitly release resources when they are no longer needed. But you can use it for any other reason and benefit the using operator !

Here is the additional code in my EntityBase class:

protected IDisposable NotifyChange(params string[] propertyNames)
{
    return new PropertyChange(this, propertyNames);
}

private class PropertyChange : IDisposable
{
    private ModelEntityBase entity;
    private readonly string[] propertyNames;

    public PropertyChange(ModelEntityBase entity, string[] propertyNames)
    {
        this.entity = entity;
        this.propertyNames = propertyNames;

        foreach (var propertyName in propertyNames)
        {
            this.entity.RaisePropertyChanging(propertyName);                    
        }
    }

    public void Dispose()
    {
        foreach (var propertyName in propertyNames)
        {
            this.entity.RaisePropertyChanged(propertyName);                    
        }

        this.entity = null;
    }
}

Not that if setting your property might invalidate other properties as well, you can give more than one parameter to the NotifyChange method.

Hope this helps !