创建wp7自定义搜索控件SearchBox

本文介绍了一种基于TextBox自定义的搜索控件,新增了六种依赖属性,包括Hint、MinCharacters、Text、ErrorMessage、HighLightBorderBrush和Command。文章详细展示了控件的功能特性、依赖属性设置及样式模板。

该自定义搜索控件继承TextBox,并且又添加了6种自定义依赖属性,分别为

Hint:暗示输入类型

MinCharacts:检验最少输入字符,如果小于该值则不能执行搜索命令

Text:该值重写了TextBox的Text属性,并且可以及时更新Text值,而不是等到失去焦点的时候才去更新

ErrorMessage:错误信息,当检验不符合条件时候在右下方显示error信息

HighLightBorderBrush:当有错误信息时候,给SearchBox添加指定颜色的边框

Command:按回车键时候,当验证通过时候执行搜索命令



效果图

    

SearchBox.cs 依赖属性声明:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace CommonUI.CustomControls
{
    /// <summary>
    /// A custom search control
    /// </summary>
    public class SearchBox : TextBox
    {
        private ContentControl HintContent;
        private TextBlock ErrorContent;

        public static readonly DependencyProperty HintProperty =
            DependencyProperty.Register("Hint", typeof(string), typeof(SearchBox), new PropertyMetadata(OnHintPropertyChanged));

        public static readonly DependencyProperty MinCharactersPerperty =
            DependencyProperty.Register("MinCharacters", typeof(int), typeof(SearchBox), new PropertyMetadata(0));

        public static readonly new DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(SearchBox), new PropertyMetadata(default(string), OnTextChanged));

        public static readonly new DependencyProperty ErrorMessageProperty =
           DependencyProperty.Register("ErrorMessage", typeof(string), typeof(SearchBox), new PropertyMetadata(null));

        public static readonly new DependencyProperty HighLightBorderBrushProperty =
           DependencyProperty.Register("HighLightBorderBrush", typeof(Brush), typeof(SearchBox), new PropertyMetadata(null));

        public static readonly new DependencyProperty CommandProperty =
           DependencyProperty.Register("Command", typeof(ICommand), typeof(SearchBox), null);

        #region Properties fields

        /// <summary>
        /// Get and set methods for the Text dependency property value.
        /// so that the value can update immediately
        /// </summary>
        public new string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        /// <summary>
        /// Get and set methods for the ErrorMessage dependency Property value.
        /// </summary>
        public string ErrorMessage
        {
            get { return (string)GetValue(ErrorMessageProperty); }
            set { SetValue(ErrorMessageProperty, value); }
        }

        /// <summary>
        /// Get and set methods for the HighLightBorderBrush dependency property value.
        /// </summary>
        public Brush HighLightBorderBrush
        {
            get { return (Brush)GetValue(HighLightBorderBrushProperty); }
            set { SetValue(HighLightBorderBrushProperty, value); }
        }

        /// <summary>
        /// Get and set methods for the Hint dependency property value.
        /// </summary>
        public string Hint
        {
            get { return (string)GetValue(HintProperty); }
            set { this.SetValue(HintProperty, value); }
        }

        /// <summary>
        /// Get and set methods for the MinCharacters dependency property value.
        /// the default value is 0, if the value is bigger than 0, the control will check the length and show the highlight border
        /// </summary>
        public int MinCharacters
        {
            get { return (int)this.GetValue(MinCharactersPerperty); }
            set { this.SetValue(MinCharactersPerperty, value); }
        }

        /// <summary>
        /// Get and set methods for the Command dependency property value.
        /// Command triggered when the KeyUp with the ENTER key occurs.
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        #endregion

        public SearchBox()
        {
            DefaultStyleKey = this.GetType();
            base.TextChanged += (s, e) =>
            {
                Text = base.Text;
            };
        }

        #region Override methods

        protected override void OnKeyUp(KeyEventArgs e)
        {
         if (!string.IsNullOrEmpty(this.Text))
         {
            if (e.Key == Key.Enter && this.Text.Length >= this.MinCharacters)
            {
                this.Command.Execute(this.Text);
            }
            if (e.Key == Key.Unknown && this.Text.Length >= this.MinCharacters)
            {
                if (e.PlatformKeyCode == 10)
                {
                    this.Command.Execute(this.Text);
                }
            }
          }
	}
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.HintContent = this.GetTemplateChild("hintContent") as ContentControl;
            this.ErrorContent = this.GetTemplateChild("errorContent") as TextBlock;
            if (ErrorContent != null)
            {
                HideErrorContent(true);
            }
            if (HintContent != null)
            {
                DetermineHintContentVisibility();
            }
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            if (HintContent != null && string.IsNullOrEmpty(this.Text))
            {
                this.HintContent.Visibility = Visibility.Collapsed;
            }
            if (((SolidColorBrush)this.BorderBrush).Color == Color.FromArgb(191, 255, 255, 255))
            {
                this.BorderBrush = new SolidColorBrush(Colors.White);
            }

            base.OnGotFocus(e);
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {
            if (HintContent != null && string.IsNullOrEmpty(this.Text))
            {
                this.HintContent.Visibility = Visibility.Visible;
                this.ClearValue(BorderBrushProperty);
                HideErrorContent(true);
            }
            if (((SolidColorBrush)this.BorderBrush).Color == Colors.White)
            {
                this.ClearValue(BorderBrushProperty);
            }

            base.OnLostFocus(e);
        }

        #endregion

        #region Private methods

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SearchBox txt = d as SearchBox;
            txt.Text = (string)e.NewValue;
            if (txt.Text.Length < (int)d.GetValue(MinCharactersPerperty))
            {
                txt.BorderBrush = txt.GetValue(HighLightBorderBrushProperty) as Brush;
                txt.HideErrorContent(false);
            }
            else
            {
                if ((int)d.GetValue(MinCharactersPerperty) != 0)
                {
                    txt.HideErrorContent(true);
                    txt.BorderBrush = new SolidColorBrush(Colors.White);
                }
            }
        }

        private static void OnHintPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            SearchBox textBox = sender as SearchBox;
            if (textBox != null && textBox.HintContent != null)
            {
                textBox.DetermineHintContentVisibility();
            }
        }

        private void HideErrorContent(bool hide)
        {
            this.ErrorContent.Visibility = hide ? Visibility.Collapsed : Visibility.Visible;
        }

        private void DetermineHintContentVisibility()
        {
            if (string.IsNullOrEmpty(this.Text))
            {
                this.HintContent.Visibility = Visibility.Visible;
            }
            else
            {
                this.HintContent.Visibility = Visibility.Collapsed;
            }
        }

        #endregion
    }
}


Style:SearchBox.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:local="clr-namespace:CommonUI.CustomControls">

    <Style TargetType="local:SearchBox">
        <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
        <Setter Property="Background" Value="{StaticResource PhoneTextBoxBrush}"/>
        <Setter Property="Foreground" Value="{StaticResource PhoneTextBoxForegroundBrush}"/>
        <Setter Property="BorderBrush" Value="{StaticResource PhoneTextBoxBrush}"/>
        <Setter Property="SelectionBackground" Value="{StaticResource PhoneAccentBrush}"/>
        <Setter Property="SelectionForeground" Value="{StaticResource PhoneTextBoxSelectionForegroundBrush}"/>
        <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
        <Setter Property="Padding" Value="2"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:SearchBox">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="ReadOnly">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DisabledOrReadonlyContent">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxReadOnlyBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid Background="Transparent" Grid.Row="0" Margin="{TemplateBinding Margin}">
                            <Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
                                <Grid>
                                    <ContentControl x:Name="hintContent" Content="{TemplateBinding Hint}" HorizontalAlignment="Left" Background="Transparent" Opacity="0.5"/>
                                    <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
                                </Grid>
                            </Border>
                            <Border x:Name="DisabledOrReadonlyBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Margin="{StaticResource PhoneTouchTargetOverhang}" Visibility="Collapsed">
                                <TextBox x:Name="DisabledOrReadonlyContent" Background="Transparent" Foreground="{StaticResource PhoneDisabledBrush}"
                                         FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontSize="{TemplateBinding FontSize}"
                                         FontFamily="{TemplateBinding FontFamily}" IsReadOnly="True" SelectionForeground="{TemplateBinding SelectionForeground}"
                                         SelectionBackground="{TemplateBinding SelectionBackground}" TextAlignment="{TemplateBinding TextAlignment}"
                                         Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"
                                         HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"
                                         TextWrapping="{TemplateBinding TextWrapping}" Text="{TemplateBinding Text}"/>
                            </Border>
                        </Grid>
                        <TextBlock x:Name="errorContent" Grid.Row="1" Text="{TemplateBinding ErrorMessage}" Style="{StaticResource ErrorContentStyle}" Foreground="{TemplateBinding HighLightBorderBrush}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="TextBlock" x:Key="ErrorContentStyle">
        <Setter Property="Margin" Value="0,-10,10,0"/>
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="HorizontalAlignment" Value="Right"/>
    </Style>
</ResourceDictionary>

页面

<local:SearchBox Hint="{Binding User.CustomerSearchHint, Source={StaticResource LocalizationManager}}"                             x:Name="searchBorder" Padding="5" MinCharacters="3" HighLightBorderBrush="Red" BorderThickness="3"                             HorizontalAlignment="Stretch"  Text="{Binding SearchString, Mode=TwoWay}" ErrorMessage="{Binding User.ErrorSearchString, Source={StaticResource LocalizationManager}}" Command="{Binding SearchCommand}"/>


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值