在上一篇中,介紹了如何實現類似QQ中分組面板的功能。這一次將介紹如何用另一種方式實現這個功能,並添加動畫效果。
在上一篇所介紹的方式中,主要的技術點其實就是那個作為ItemsPanel的自定義Panel。然而這種實現方式有兩個主要缺點。
1.沒有了Virtualizing的效果。雖然沒有不可見項。
2.不便於添加動畫效果。
這裡將向大家介紹另一種實現方式。就是用Blend 3中非常火爆的Behavior來實現,並且可以很容易地添加上動畫效果。
這個Behavior原理很簡單,就是動態地計算ListBox裡Item的高度。這就要求:
1.不能為ListBox的Item指定各不相同的高度。
2.要為每個Item指定一個默認的收縮時的高度。
在Rooijakkers的博客上介紹了類似的用高度的方法。不過上面的方法沒有充分利用WPF的特性,寫了一些不必要的邏輯,比如控件Expander 的IsExpanded屬性。而且沒有動畫的支持。
這裡使用Behavior簡單步驟就是,添加一個用於ListBox的自定義Behavior,然後在ListBox的SelectionChanged事件中去設置每個Item的高 度。用Storyboard就可以很容易地實現動畫效果。
這個Behavior有兩個自定義屬性。一個是DefaultHeight,一個是AnimationDuration。顧名思義,不解釋了。核心代碼如下所示。
Core Logic
private void OnAssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
{
double selectedItemFinalHeight = AssociatedObject.ActualHeight;
Storyboard storyBoard = new Storyboard();
for (int i = 0; i < AssociatedObject.Items.Count; i++)
{
ListBoxItem item = AssociatedObject.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
if (!item.IsSelected)
{
selectedItemFinalHeight -= DefaultHeight;
DoubleAnimation heightAnimation = new DoubleAnimation()
{
To = DefaultHeight,
Duration = new Duration(new TimeSpan(0, 0, 0, 0, AnimationDuration))
};
Storyboard.SetTarget(heightAnimation, item);
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath (FrameworkElement.HeightProperty));
storyBoard.Children.Add(heightAnimation);
}
}
// The Padding of the ListBox.
selectedItemFinalHeight -= 4;
if (AssociatedObject.SelectedIndex >= 0)
{
ListBoxItem selectedItem = AssociatedObject.ItemContainerGenerator.ContainerFromIndex (AssociatedObject.SelectedIndex) as ListBoxItem;
DoubleAnimation fillheightAnimation = new DoubleAnimation()
{
To = selectedItemFinalHeight,
Duration = new Duration(new TimeSpan(0, 0, 0, 0, AnimationDuration))
};
Storyboard.SetTarget(fillheightAnimation, selectedItem);
Storyboard.SetTargetProperty(fillheightAnimation, new PropertyPath (FrameworkElement.HeightProperty));
storyBoard.Children.Add(fillheightAnimation);
}
storyBoard.Begin(AssociatedObject);
}
這個示例看截圖是和上一篇中介紹的是一樣。要看動畫效果還是要自己試一下的。在這個代碼裡,也包含了上次的示例。
本文配套源碼