上文介紹自定義 Panel 實現 QQ 分組面板,但有兩大缺點:失去虛擬化效能、難以添加動畫。本文使用 Blend 3 Behavior 重新實現,輕鬆添加動畫效果。
動態計算 ListBox 中 Item 高度。前提條件:
優於前人方案:充分利用 WPF 特性、無冗餘邏輯(如 Expander.IsExpanded)、完整動畫支援。
SelectionChanged 事件中設定每個 Item 高度Storyboard + DoubleAnimation 實現平滑動畫DefaultHeight:收合狀態高度AnimationDuration:動畫持續時間(毫秒)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(TimeSpan.FromMilliseconds(AnimationDuration))
};
Storyboard.SetTarget(heightAnimation, item);
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(FrameworkElement.HeightProperty));
storyBoard.Children.Add(heightAnimation);
}
}
// 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(TimeSpan.FromMilliseconds(AnimationDuration))
};
Storyboard.SetTarget(fillHeightAnimation, selectedItem);
Storyboard.SetTargetProperty(fillHeightAnimation, new PropertyPath(FrameworkElement.HeightProperty));
storyBoard.Children.Add(fillHeightAnimation);
}
storyBoard.Begin(AssociatedObject);
}
動畫效果需親自運行體驗。本文配套完整原始碼可下載。