views:

293

answers:

1

I have a ListView that is set up with a MinHeight and a MaxHeight. The final height is determined by the number of items inside the list.

At the moment, when a list is added to the ItemsSource property of the ListView, the height jumps to the final height. Is there a way to animate this change in height, so that it's smooth?

+1  A: 

Here's an example of something that does what you want (as I understand it). I'll call this "quick and dirty" and don't claim to have put a whole lot of thought into it.

    public class CustomListView : ListView
    {
        public bool IsAttached
        {
            get { return (bool)GetValue(IsAttachedProperty); }
            set { SetValue(IsAttachedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsAttached.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsAttachedProperty =
            DependencyProperty.Register("IsAttached", 
                typeof(bool), 
                typeof(CustomListView), 
                new UIPropertyMetadata(false));
    }

    public class ViewModel : INotifyPropertyChanged
    {
        public void PopulateItems()
        {
            Items = new List<string>();

            for (var i = 0; i < 200; i++ )
            {
                Items.Add("The quick brown fox jumps over the lazy dog.");
            }
            InvokePropertyChanged(new PropertyChangedEventArgs("Items"));

            IsAttached = true;
            InvokePropertyChanged(new PropertyChangedEventArgs("IsAttached"));
        }

        public List<string> Items { get; private set; }
        public bool IsAttached { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private void InvokePropertyChanged(PropertyChangedEventArgs e)
        {
            var changed = PropertyChanged;

            if (changed != null)
            {
                changed(this, e);
            }
        }
    }

<Window x:Class="AnimateHeight.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AnimateHeight"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <Button Width="100" Content="Add Items" Click="OnClickAddItems"/>
        <local:CustomListView x:Name="VariableListView" ItemsSource="{Binding Items}" IsAttached="{Binding IsAttached}" >
            <local:CustomListView.Style>
                <Style TargetType="{x:Type local:CustomListView}">
                    <Setter Property="MinHeight" Value="50" />
                    <Setter Property="MaxHeight" Value="50" />
                    <Style.Triggers>
                        <Trigger Property="IsAttached" Value="true">
                            <Trigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation 
                                            Storyboard.TargetProperty="(ListView.MaxHeight)" 
                                            To="150" 
                                            Duration="0:0:5"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </local:CustomListView.Style>
        </local:CustomListView>
    </StackPanel>
</Window>

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            DataContext = new ViewModel();
        }

        private void OnClickAddItems(object sender, RoutedEventArgs e)
        {
            ((ViewModel)DataContext).PopulateItems();
        }
    }

UPDATE: You should be able to copy this into .cs and .xaml files and run it as an example application. To summarize what I'm doing: Set the MaxHeight property to something artificially low, in my case I just set it to the same value as the MinHeight. Then you can create a storyboard that animates the MaxHeight to its real value, which gives you the smooth transition effect. The trick is indicating when to start the animation, I use a dependency property in a subclassed ListView just because that seemed to be the easiest option to implement in a hurry. I just have to bind the dependency property to a value in my ViewModel and I can trigger the animation by changing that value (since I don't know of an easy way to trigger an animation based on a change to a ListView ItemsSource off the top of my head).

MichaC