WPF 自定义标题栏 自定义菜单栏
自定义标题栏
自定义列表,可以直接修改WPF中的ListBox模板,也用这样类似的效果。但是ListBox是不能设置默认选中状态的。
而我们需要一些复杂的UI效果,还是直接自定义控件来的快
GitHub下载地址:https://github.com/Kybs0/MenuListControl
一、设计界面样式

<UserControl x:Class="WpfApplication6.TitleListControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="800" Loaded="TitleListControl_OnLoaded" > <UserControl.Resources> <Style x:Key="FirstButtonStyle" TargetType="RadioButton"> <Setter Property="Margin" Value="0.5,2"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RadioButton}"> <Grid> <Border x:Name="ButtonBorder" Height="35" Width="100" Background="#FF286E9E" CornerRadius="15,0,0,15"></Border> <TextBlock Text="{TemplateBinding Content}" Foreground="White" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="ButtonBorder" Property="Background" Value="DeepSkyBlue"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="RadioButton"> <Setter Property="Margin" Value="0.5,2"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RadioButton}"> <Grid> <Border x:Name="ButtonBorder" Height="35" Width="100" Background="#FF286E9E"></Border> <TextBlock Text="{TemplateBinding Content}" Foreground="White" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="ButtonBorder" Property="Background" Value="DeepSkyBlue"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="LastButtonStyle" TargetType="RadioButton"> <Setter Property="Margin" Value="0.5,2"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RadioButton}"> <Grid> <Border x:Name="ButtonBorder" Height="35" Width="100" Background="#FF286E9E" CornerRadius="0,15,15,0"></Border> <TextBlock Text="{TemplateBinding Content}" Foreground="White" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="ButtonBorder" Property="Background" Value="DeepSkyBlue"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <Grid> <Border x:Name="ControlBorder" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="16,16,16,16"> <Border.Background> <LinearGradientBrush StartPoint="0,1" EndPoint="1,1"> <GradientStop Color="White" Offset="0.2"></GradientStop> <GradientStop Color="DeepSkyBlue" Offset="1"></GradientStop> </LinearGradientBrush> </Border.Background> <StackPanel x:Name="SpTitleList" Orientation="Horizontal" Background="Transparent" Margin="2,0"> </StackPanel> </Border> </Grid> </UserControl>
二、控件后台代码

public partial class TitleListControl : UserControl { public TitleListControl() { InitializeComponent(); } /// <summary> /// get or set the items /// </summary> public List<TitleListItemModel> TitleListItems { get { return (List<TitleListItemModel>) GetValue(TitleListItemsProperty); } set{SetValue(TitleListItemsProperty,value);} } public static readonly DependencyProperty TitleListItemsProperty = DependencyProperty.Register("TitleListItems", typeof(List<TitleListItemModel>), typeof(TitleListControl),new PropertyMetadata(new List<TitleListItemModel>())); public UIElementCollection Items { get { return SpTitleList.Children; } } private void TitleListControl_OnLoaded(object sender, RoutedEventArgs e) { if (TitleListItems!=null) { var items = TitleListItems; int index = 0; foreach (var item in items) { var radiaoButton=new RadioButton() { Content = item.Name }; if (index == 0) { radiaoButton.Style = GetStyle("first"); } else if (index == items.Count - 1) { radiaoButton.Style = GetStyle("last"); } item.Index = index; radiaoButton.DataContext = item; radiaoButton.Checked += ToggleButton_OnChecked; SpTitleList.Children.Add(radiaoButton); index++; } } } private Style GetStyle(string type) { Style style = null; switch (type) { case "first": { style = this.Resources["FirstButtonStyle"] as Style; } break; case "last": { style = this.Resources["LastButtonStyle"] as Style; } break; } return style; } private void ToggleButton_OnChecked(object sender, RoutedEventArgs e) { var radioButton=sender as RadioButton; var dataModel=radioButton.DataContext as TitleListItemModel; int index = dataModel.Index; int count = SpTitleList.Children.Count; var linerBrush = new LinearGradientBrush(){StartPoint=new Point(0,1),EndPoint = new Point(1,1)}; if (index==0) { linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.White, Offset = 0.2 }); linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.DeepSkyBlue, Offset = 1 }); } else if (index == count - 1) { linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.DeepSkyBlue, Offset = 0 }); linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.White, Offset = 0.8 }); } else { double offsetValue = Convert.ToDouble(index) / count; linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.DeepSkyBlue, Offset = 0 }); linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.White, Offset = offsetValue }); linerBrush.GradientStops.Add(new GradientStop() { Color = Colors.DeepSkyBlue, Offset = 1 }); } ControlBorder.Background = linerBrush; } } public class TitleListItemModel { public int Index { get; set; } public string Name { get; set; } public string Remark { get; set; } }
三、引用UserControl

<Window x:Class="WpfApplication6.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpfApplication6="clr-namespace:WpfApplication6" Title="MainWindow" Height="350" Width="800" Background="LightGray"> <Grid> <wpfApplication6:TitleListControl VerticalAlignment="Center" HorizontalAlignment="Center"> <wpfApplication6:TitleListControl.TitleListItems> <wpfApplication6:TitleListItemModel Name="综合" ></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="语音体验" ></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="网页浏览"></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="视频播放" ></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="综合覆盖"></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="速率性能"></wpfApplication6:TitleListItemModel> <wpfApplication6:TitleListItemModel Name="网络延时"></wpfApplication6:TitleListItemModel> </wpfApplication6:TitleListControl.TitleListItems> </wpfApplication6:TitleListControl> </Grid> </Window>
如需要控件的SelectionChanged方法,在UserControl中添加个委托或者注册一个事件即可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)