WPF 搜索框控件样式
完全通过Xaml代码实现,使用了UserControl进行封装。功能包括聚焦时控件展开,输入为空时的文字提示,以及待选提示项列表等效果。实现效果如下图:
xaml代码
xml
<UserControl x:Class="SearchBar.SearchBox"
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"
xmlns:local="clr-namespace:SearchBar"
UseLayoutRounding="True"
TextElement.FontSize="14"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="440">
<UserControl.Resources>
<SolidColorBrush x:Key="Control.BoderBrush" Color="#CBCBCB"/>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#FFF2F3F4"/>
<Setter Property="BorderBrush" Value="{StaticResource Control.BoderBrush}"/>
<Setter Property="Foreground" Value="#515151"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="8 0 0 0"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" CornerRadius="8" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="44"/>
</Grid.ColumnDefinitions>
<Border x:Name="bdLeft" CornerRadius="8" Margin="4 4 8 4">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBlock Text="输入搜索内容" VerticalAlignment="Center" Margin="10 0" Opacity="0.8">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=TextBox},Path=Text}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
<Button Grid.Column="1" Margin="4">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="bd" CornerRadius="8" Background="Transparent">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"></ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="#60CACACA"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
<Path Fill="#C9000000" Margin="8" Stretch="Uniform" Data="M15.7 13.3l-3.81-3.83A5.93 5.93 0 0013 6c0-3.31-2.69-6-6-6S1 2.69 1 6s2.69 6 6 6c1.3 0 2.48-.41 3.47-1.11l3.83 3.81c.19.2.45.3.7.3.25 0 .52-.09.7-.3a.996.996 0 000-1.41v.01zM7 10.7c-2.59 0-4.7-2.11-4.7-4.7 0-2.59 2.11-4.7 4.7-4.7 2.59 0 4.7 2.11 4.7 4.7 0 2.59-2.11 4.7-4.7 4.7z"></Path>
</Button>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="white"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Background" TargetName="bdLeft" Value="#60CACACA"/>
<Setter Property="BorderBrush" TargetName="border" Value="Transparent"/>
<Setter Property="Background" TargetName="border" Value="white"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="44"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" BorderThickness="1" Background="White" BorderBrush="{StaticResource Control.BoderBrush}" CornerRadius="8">
<Border.Effect>
<DropShadowEffect Color="Gray" Opacity="0.2" ShadowDepth="0" BlurRadius="12"/>
</Border.Effect>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtBox,Path=IsKeyboardFocused}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid Margin="0 44 0 12">
<ListBox BorderBrush="Transparent" Padding="4 0"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SearchBox},Path=SearchList}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="8" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ContentPresenter Opacity="0.8" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#20808080"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#20808080"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="#20808080"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</Border>
<Grid>
<TextBox x:Name="txtBox"/>
</Grid>
<Grid Grid.Row="1" Height="280"></Grid>
</Grid>
</UserControl>
后台代码:
csharp
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SearchBar
{
/// <summary>
/// SearchBox.xaml 的交互逻辑
/// </summary>
public partial class SearchBox : UserControl
{
public SearchBox()
{
InitializeComponent();
}
public ObservableCollection<string> SearchList
{
get { return (ObservableCollection<string>)GetValue(SearchListProperty); }
set { SetValue(SearchListProperty, value); }
}
public static readonly DependencyProperty SearchListProperty =
DependencyProperty.Register("SearchList", typeof(ObservableCollection<string>), typeof(SearchBox), new PropertyMetadata(new ObservableCollection<string>()));
}
}
控件使用显示示例:
xml
<Window x:Class="SearchBar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SearchBar"
mc:Ignorable="d"
Title="MainWindow" Height="500" Width="420">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:SearchBox x:Name="searchbox" Grid.RowSpan="2" Margin="8" Panel.ZIndex="50">
</local:SearchBox>
<ListBox Grid.Row="1" Margin="16">
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
<ListBoxItem Padding="8">AAA</ListBoxItem>
</ListBox>
</Grid>
</Window>