一.前言 html
申明:WPF自定義控件與樣式是一個系列文章,先後是有些關聯的,但大可能是按照由簡到繁的順序逐步發佈的等,如有不明白的地方能夠參考本系列前面的文章,文末附有部分文章連接。 ide
本文主要內容: post
二.菜單Menu的自定義樣式 學習
自定義菜單樣式的效果圖: 字體
Menu和ContextMenu樣式自己很簡單,他們最主要的部分就是MenuItem,MenuItem中包含的內容比較多,如圖標、選中狀態、二級菜單、二級菜單的指針、快捷鍵等。 使用了字體圖標定義菜單項MenuItem樣式代碼: 大數據
<!--菜單項MenuItem樣式FIconMenuItem--> <Style x:Key="FIconMenuItem" TargetType="{x:Type MenuItem}"> <Setter Property="BorderBrush" Value="{StaticResource MenuBorderBrush}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Background" Value="{StaticResource MenuBackground}"/> <Setter Property="Foreground" Value="{StaticResource MenuForeground}"/> <Setter Property="FontSize" Value="{StaticResource FontSize}"/> <Setter Property="Height" Value="28"/> <Setter Property="Width" Value="Auto"/> <Setter Property="Margin" Value="1"/> <Setter Property="local:ControlAttachProperty.FIconSize" Value="22"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type MenuItem}"> <!--Item--> <Border x:Name="border" Background="Transparent" Height="{TemplateBinding Height}" Opacity="1"> <Grid VerticalAlignment="Center" Margin="{TemplateBinding Margin}"> <Grid.ColumnDefinitions> <ColumnDefinition x:Name="icon_col" MaxWidth="35" SharedSizeGroup="MenuItemIconColumnGroup"/> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuTextColumnGroup"/> <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/> <ColumnDefinition Width="16" x:Name="arrow_col" SharedSizeGroup="MenumItemArrow"/> </Grid.ColumnDefinitions> <!--icon--> <TextBlock x:Name="PART_Icon" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding Foreground}" Margin="5,1,1,1" FontSize="{TemplateBinding local:ControlAttachProperty.FIconSize}" Style="{StaticResource FIcon}"/> <!--Header--> <ContentPresenter Grid.Column="1" x:Name="txtHeader" Margin="3,1,5,1" MinWidth="90" RecognizesAccessKey="True" VerticalAlignment="Center" ContentSource="Header"/> <!--快捷鍵 InputGestureText 暫不支持你了 --> <TextBlock Grid.Column="2" Margin="3,1,3,1" x:Name="IGTHost" Text="{TemplateBinding InputGestureText}" FontSize="{TemplateBinding FontSize}" VerticalAlignment="Center" Visibility="Visible" Foreground="{TemplateBinding Foreground}" /> <!--右指針--> <TextBlock x:Name="PART_Arrow" Grid.Column="3" Text="" Foreground="{TemplateBinding Foreground}" FontSize="14" Style="{StaticResource FIcon}"/> <!--淡出子集菜單容器--> <Popup x:Name="SubMenuPopup" AllowsTransparency="true" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" Focusable="false" VerticalOffset="0" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}"> <Border Background="{TemplateBinding Background}" CornerRadius="0" Margin="5" Effect="{StaticResource DefaultDropShadow}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True"> <StackPanel Margin="0" IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/> </Grid> </Border> </Popup> </Grid> </Border> <!--觸發器--> <ControlTemplate.Triggers> <!--TopLevelHeader:第一級菜單(有子菜單)--> <Trigger Property="Role" Value="TopLevelHeader"> <Setter Property="Visibility" Value="Collapsed" TargetName="PART_Arrow"/> <Setter Property="Visibility" Value="Collapsed" TargetName="IGTHost"/> <Setter Property="Margin" Value="5,1,1,1" TargetName="PART_Icon"/> <Setter Property="Margin" Value="1,1,6,1" TargetName="txtHeader"/> <Setter Property="MinWidth" Value="10" TargetName="txtHeader"/> <Setter Property="Width" Value="0" TargetName="arrow_col"/> </Trigger> <!--TopLevelItem 第一級菜單(無子級)--> <Trigger Property="Role" Value="TopLevelItem"> <Setter Property="Visibility" Value="Collapsed" TargetName="PART_Arrow"/> <Setter Property="Visibility" Value="Collapsed" TargetName="IGTHost"/> <Setter Property="Margin" Value="5,1,1,1" TargetName="PART_Icon"/> <Setter Property="Margin" Value="1,1,6,1" TargetName="txtHeader"/> <Setter Property="MinWidth" Value="10" TargetName="txtHeader"/> <Setter Property="Width" Value="0" TargetName="arrow_col"/> </Trigger> <!--SubmenuHeader:子菜單,有子菜單--> <Trigger Property="Role" Value="SubmenuHeader"> <Setter Property="Visibility" Value="Visible" TargetName="PART_Arrow"/> <Setter Property="Placement" Value="Right" TargetName="SubMenuPopup"/> </Trigger> <!--SubMenuItem:子菜單,無子級--> <Trigger Property="Role" Value="SubMenuItem"> <Setter Property="Visibility" Value="Collapsed" TargetName="PART_Arrow"/> </Trigger> <!--選中狀態,優先級將高於Icon--> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="PART_Icon" Value="" Property="Text"></Setter> <Setter TargetName="PART_Icon" Value="18" Property="FontSize"></Setter> <Setter TargetName="PART_Icon" Value="{StaticResource CheckedForeground}" Property="Foreground"></Setter> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="border" Value="{StaticResource DisableOpacity}" Property="Opacity"></Setter> </Trigger> <!--高亮狀態--> <Trigger Property="IsHighlighted" Value="true"> <Setter Property="Background" TargetName="border" Value="{StaticResource MenuMouseOverBackground}"></Setter> <Setter Property="Foreground" Value="{StaticResource MenuMouseOverForeground}"></Setter> </Trigger> <Trigger Property="IsPressed" Value="true"> <Setter Property="Background" TargetName="border" Value="{StaticResource MenuPressedBackground}"></Setter> <Setter Property="Foreground" Value="{StaticResource MenuPressedForeground}"></Setter> </Trigger> <!--子菜單打開狀態--> <Trigger Property="IsSubmenuOpen" Value="true" > <Setter TargetName="PART_Arrow" Value="{StaticResource CheckedForeground}" Property="Foreground"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--基於FIconMenuItem的默認樣式,提供Header模板--> <Style x:Key="DefaultMenuItem" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource FIconMenuItem}"> <Setter Property="HeaderTemplate"> <Setter.Value> <DataTemplate> <TextBlock x:Name="txtHeader" FontSize="{Binding FontSize,RelativeSource={RelativeSource AncestorType={x:Type MenuItem},Mode=FindAncestor}}" HorizontalAlignment="Stretch" Margin="3,1,5,1" Text="{Binding Header,RelativeSource={RelativeSource AncestorType={x:Type MenuItem},Mode=FindAncestor}}" VerticalAlignment="Center" Foreground="{Binding Foreground,RelativeSource={RelativeSource AncestorType={x:Type MenuItem},Mode=FindAncestor}}"/> </DataTemplate> </Setter.Value> </Setter> </Style>
Menu樣式: this
<!--默認Menu樣式--> <Style x:Key="DefaultMenu" TargetType="{x:Type Menu}"> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" /> <Setter Property="TextOptions.TextFormattingMode" Value="Ideal" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="ItemContainerStyle" Value="{StaticResource DefaultMenuItem}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Menu}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> <ItemsPresenter Margin="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
示例代碼: url
<MenuItem Header="幫助(H)" InputGestureText="Ctrl+H" Icon="" > <MenuItem Header="設置" Icon=""/> <MenuItem Icon="" Header="插件管理" /> <MenuItem Icon="" Header="用戶管理" /> <MenuItem Icon="" Header="修改密碼" /> <MenuItem Icon="" Header="在線更新" /> <Separator Style="{StaticResource HorizontalSeparatorStyle}"/> <MenuItem Icon="" Header="問題反饋" /> <MenuItem Icon="" Header="技術支持" /> <MenuItem Icon="" Header="幫助" /> <MenuItem Icon="" Header="關於" /> </MenuItem>
三.右鍵菜單ContextMenu的自定義樣式 spa
有了第二節的MenuItem樣式,ContextMenu的樣式很簡單: pwa
<!--默認右鍵菜單ContextMenu樣式--> <Style x:Key="DefaultContextMenu" TargetType="{x:Type ContextMenu}"> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" /> <Setter Property="TextOptions.TextFormattingMode" Value="Ideal" /> <Setter Property="BorderBrush" Value="{StaticResource MenuBorderBrush}"/> <Setter Property="Background" Value="{StaticResource MenuBackground}"/> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Foreground" Value="{StaticResource MenuForeground}"/> <Setter Property="OverridesDefaultStyle" Value="True" /> <Setter Property="Grid.IsSharedSizeScope" Value="True" /> <Setter Property="HasDropShadow" Value="True" /> <Setter Property="ItemContainerStyle" Value="{StaticResource DefaultMenuItem}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ContextMenu}"> <Grid> <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" Margin="5" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" Margin="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle" /> </Border> </Grid> <ControlTemplate.Triggers> <Trigger Property="HasDropShadow" Value="True"> <Setter TargetName="Border" Property="Effect" Value="{StaticResource DefaultDropShadow}"> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
實現一個文本操做(剪切、複製、粘貼)的樣式:
<!--文本操做右鍵菜單--> <ContextMenu x:Key="TextBoxContextMenu" Style="{StaticResource DefaultContextMenu}"> <MenuItem Command="ApplicationCommands.Cut" Icon="" Style="{DynamicResource DefaultMenuItem}" /> <MenuItem Command="ApplicationCommands.Copy" Icon="" Style="{DynamicResource DefaultMenuItem}" /> <MenuItem Command="ApplicationCommands.Paste" Icon="" Style="{DynamicResource DefaultMenuItem}" /> </ContextMenu>
效果圖:
四.樹控件TreeView的自定義樣式
4.1TreeView基本樣式
TreeView的樣式比較簡單,相比ListBox,主要多了層級關係,節點的展開、收縮。效果圖:
樣式定義中默認是開啓虛擬化,以支持大數據,數據很少時最好關閉。樣式代碼:
<!--TreeViewItem默認樣式--> <Style x:Key="DefaultTreeViewItem" TargetType="{x:Type TreeViewItem}"> <Setter Property="MinHeight" Value="25" /> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="Margin" Value="0" /> <Setter Property="local:ControlAttachProperty.FIconSize" Value="19"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TreeViewItem}"> <StackPanel> <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" MinHeight="{TemplateBinding MinHeight}" UseLayoutRounding="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> <!--多層級間隔,暫緩--> <!--<Grid Margin="{Binding Converter={StaticResource LengthConverter}, RelativeSource={x:Static RelativeSource.TemplatedParent}}"--> <Grid Margin="{TemplateBinding Margin}" VerticalAlignment="Stretch"> <Grid.ColumnDefinitions> <ColumnDefinition MinWidth="18" Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <!--展開收縮按鈕--> <ToggleButton x:Name="ExpanderBtn" IsChecked="{Binding Path=IsExpanded, RelativeSource={x:Static RelativeSource.TemplatedParent}, Mode=TwoWay}" ClickMode="Press" > <ToggleButton.Template> <ControlTemplate TargetType="ToggleButton"> <Border> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </Border> </ControlTemplate> </ToggleButton.Template> <ToggleButton.Content> <TextBlock x:Name="ExpanderIcon" Foreground="{TemplateBinding Foreground}" Text="" Style="{StaticResource FIcon}" FontSize="{TemplateBinding local:ControlAttachProperty.FIconSize}" /> </ToggleButton.Content> </ToggleButton> <!--內容--> <ContentPresenter x:Name="PART_Header" Grid.Column="1" ContentSource="Header" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> </Grid> </Border> <ItemsPresenter Margin="18,0,0,0" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </StackPanel> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="False"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" /> </Trigger> <Trigger Property="IsExpanded" Value="True"> <Setter TargetName="ExpanderIcon" Property="Text" Value="" /> </Trigger> <Trigger Property="HasItems" Value="False"> <Setter TargetName="ExpanderIcon" Property="Visibility" Value="Hidden" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="{StaticResource ItemMouseOverBackground}" /> <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}" /> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" /> <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True" /> <Condition Property="Selector.IsSelectionActive" Value="True" /> </MultiTrigger.Conditions> <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" /> <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" /> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--TreeView樣式--> <Style x:Key="DefaultTreeView" TargetType="{x:Type TreeView}"> <Setter Property="ScrollViewer.CanContentScroll" Value="True" /> <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter> <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" /> <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" /> <Setter Property="Background" Value="{StaticResource ItemsContentBackground}"/> <Setter Property="ItemContainerStyle" Value="{StaticResource DefaultTreeViewItem}"></Setter> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <VirtualizingStackPanel IsItemsHost="True" IsVirtualizing="True" VirtualizationMode="Recycling" Margin="0"/> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style>
4.2 TreeView的右鍵菜單實現
TreeView支持右鍵操做應該是比較常見的需求,實現很簡單,效果演示:
示例代碼:
<HierarchicalDataTemplate x:Key="ItemNode" DataType="{x:Type local:NodeX}" ItemsSource="{Binding Nodes}"> <StackPanel Orientation="Horizontal" Height="28"> <core:FImage Source="{Binding Icon}" Width="22" Height="22"></core:FImage> <TextBlock Text="{Binding Name}" FontSize="13" VerticalAlignment="Center" Margin="3,0,0,0"></TextBlock> </StackPanel> </HierarchicalDataTemplate> <TreeView Width="250" Margin="3" x:Name="tree1" ItemTemplate="{StaticResource ItemNode}"> <TreeView.ItemContainerStyle> <Style BasedOn="{StaticResource DefaultTreeViewItem}" TargetType="{x:Type TreeViewItem}"> <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown"/> </Style> </TreeView.ItemContainerStyle> <TreeView.ContextMenu> <ContextMenu> <MenuItem Icon="" Header="展開" Click="MenuItem_OnClick" Style="{DynamicResource DefaultMenuItem}" /> <MenuItem Icon="" Header="剪切" Style="{DynamicResource DefaultMenuItem}" /> <MenuItem Icon="" Header="賦值" Style="{DynamicResource DefaultMenuItem}" /> </ContextMenu> </TreeView.ContextMenu> </TreeView>
後臺C#代碼:
private void TreeViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; if (treeViewItem != null) { treeViewItem.Focus(); e.Handled = true; } } static DependencyObject VisualUpwardSearch<T>(DependencyObject source) { while (source != null && source.GetType() != typeof(T)) source = VisualTreeHelper.GetParent(source); return source; } private void MenuItem_OnClick(object sender, RoutedEventArgs e) { var item = this.tree1.SelectedItem as NodeX; if (item != null) { MessageBoxX.Info(item.Name.ToString()); } }
附錄:參考引用
WPF自定義控件與樣式(1)-矢量字體圖標(iconfont)
WPF自定義控件與樣式(3)-TextBox & RichTextBox & PasswordBox樣式、水印、Label標籤、功能擴展
WPF自定義控件與樣式(4)-CheckBox/RadioButton自定義樣式
WPF自定義控件與樣式(5)-Calendar/DatePicker日期控件自定義樣式及擴展
WPF自定義控件與樣式(6)-ScrollViewer與ListBox自定義樣式
WPF自定義控件與樣式(7)-列表控件DataGrid與ListView自定義樣式
WPF自定義控件與樣式(8)-ComboBox與自定義多選控件MultComboBox
版權全部,文章來源:http://www.cnblogs.com/anding
我的能力有限,本文內容僅供學習、探討,歡迎指正、交流。