現公司項目中需要制作一個扇形菜單,菜單項是用ListBox重寫Style實現的,其數據是綁定的。菜單的每一項都有Normal,MouseOver和Selected三種狀態,這三種狀態當然可以通過鼠標移動和點擊控制,但現在要通過代碼來改變控件外觀實現三種狀態切換,該如何處理呢?
1.WPF綁定的ListBox獲取ListBoxItem
WPF中如果ListBox的ItemSource為綁定的,則ListBox.Items為綁定的數據源,而非ListBoxItem。如果直接通過如下代碼會發現無法獲取ListBoxItem:
var listBoxItem = ListBox1.Items[0] as List1BoxItem;
這時提示listBoxItem為null,那該如何獲取到ListBoxItem呢?這時就用到了ItemContainerGenerator.ContainerFromIndex(int index)方法,該方法返回對應於 System.Windows.Controls.ItemCollection 中指定索引項的元素:
var listBoxItem = ListBox1.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement;
這次就獲取到了ListBox1中第一個listBoxItem。
2.WPF中的手動控制控件外觀變化
如何在不移動鼠標的情況下觸發ListBoxItem的MouseOver狀態發生呢?這時就利用到了VisualStateManager.GoToState(FrameworkElement control, string stateName, bool useTransitions)方法。該方法可以使控件在兩個狀態間隨意轉換:
首先,為項目中的ListBoxItem自定義一個Style,其包含Normal和MouseOver兩種狀態:
<Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <Storyboard> <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="rectangle"> <EasingColorKeyFrame KeyTime="0" Value="#FF5CFD30" /> </ColorAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="rectangle"> <EasingColorKeyFrame KeyTime="0" Value="#FF29B5B8" /> </ColorAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled" /> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle x:Name="rectangle" Fill="#FF5AFB2E" Stroke="Black" /> <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="{TemplateBinding Content}" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
為ListBox1應用樣式,綁定數據源,拖出兩個button分別用於設置ListBoxItem的狀態:
<Grid> <ListBox x:Name="ListBox1" HorizontalAlignment="Left" Height="100" Margin="57,45,0,0" VerticalAlignment="Top" Width="100" ItemsSource="{Binding MenuList}" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}" d:LayoutOverrides="HorizontalAlignment, VerticalAlignment" /> <Button x:Name="btnMouseOver" Content="MouseOver" HorizontalAlignment="Left" Margin="75,0,0,65.163" VerticalAlignment="Bottom" Width="75" Click="btnMouseOver_Click" /> <Button x:Name="btnNormal" Content="Normal" Margin="213,0,221,65.163" VerticalAlignment="Bottom" Click="btnNormal_Click" /> </Grid>
後台找到ListBoxItem並改變其外觀:
private void btnMouseOver_Click(object sender, RoutedEventArgs e) { var item = ListBox1.ItemContainerGenerator.ContainerFromIndex(2) as FrameworkElement; VisualStateManager.GoToState(item, "MouseOver", false); } private void btnNormal_Click(object sender, RoutedEventArgs e) { var item = ListBox1.ItemContainerGenerator.ContainerFromIndex(2) as FrameworkElement; VisualStateManager.GoToState(item, "Normal", false); }
效果: