首先来一发图:

今天主要说的textBox内部给予提示:

使用自定义控件方式:TextBoxTip继承TextBox

利用TextBox的背景画刷功能

VisualBrush是一种比较特殊的笔刷,它的功能仍然是用来给元素填充图案,但它的内容却可以是各种控件。

你可以将其理解为一个普通的容器,但在其内部的所有控件都会失去交互能力,而只保留显示能力。

                                    <TextBox.Background>
<VisualBrush Stretch="None" AlignmentX="Left">
<VisualBrush.Transform>
<TranslateTransform X="" Y=""/>
</VisualBrush.Transform>
<VisualBrush.Visual>
<TextBlock x:Name="PART_EmptyText" Grid.Column="" Text="{TemplateBinding TooTipText}"
FontSize="" Visibility="Collapsed" Foreground="{TemplateBinding Foreground}"
Focusable="False"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>

在背景色上给予一个画刷,使用textBlock来显示要提示的文本。

使用条件触发控制画刷的显示与隐藏:

                        <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFocused,ElementName=PART_Text}" Value="False"/>
<Condition Binding="{Binding Path=Text,ElementName=PART_Text}" Value=""/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_EmptyText" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>

当TextBox失去焦点和文本内容为“”等两个条件成立时 画刷显示。

文本内部还放置了一个Button用于Clear

                        <Button  Grid.Column=""
x:Name="Xbtn"
ToolTip="Clear"
Visibility="{TemplateBinding XButtonVisibility}"
VerticalAlignment="Center" Margin="7 0"
Command="{x:Static local:TextBoxTip.XButtonCommand}"
Style="{StaticResource XCloseButton}"/>

给Button注册Command事件

        /// <summary>
/// Since we're using RoutedCommands for the increase/decrease commands, we need to
/// register them with the command manager so we can tie the events
/// to callbacks in the control.
/// </summary>
private static void InitializeCommands()
{
XButtonCommand = new RoutedCommand("XButtonCommand", typeof(TextBoxTip));
CommandManager.RegisterClassCommandBinding(typeof(TextBoxTip),
new CommandBinding(XButtonCommand, CloseButtonCommand));
} public static void CloseButtonCommand(Object sender, ExecutedRoutedEventArgs e)
{
TextBoxTip control = sender as TextBoxTip;
if (control != null)
{
control.Text = "";
}
} public static RoutedCommand XButtonCommand { set; get; }

同理:TextBoxSign也继承TextBox

不过该模板中放置了两个TextBox,一个用于显示正常的数据,比如文本为:如果个性签名很长的话就会自定计算长度是否超过文本width,然后给予截取字符串显示省略号(...)

一个用于显示截取后的文本内容,ShowTip的方式是采用上面画刷方式就不再多介绍了。

关于动态计算是重写了文本Size方法,然后在方法内部使用一个根据字体,字号,字体风格,字体填充方式计算

   protected override Size ArrangeOverride(Size arrangeBounds)
{
Size size = base.ArrangeOverride(arrangeBounds);
if (NormalIsFocus == false)
{
ControlTrimming(arrangeBounds.Width);
}
return size;
}
private void ControlTrimming(double width)
{
if (!string.IsNullOrEmpty(this.Text))
{
NormalTxt.Visibility = Visibility.Hidden;
TrimmingTxt.Visibility = Visibility.Visible;
Typeface face = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch);
bool IsShowTip = false;
TrimmingTxt.Text = TrimmingHelper.Trim(Text, "...", "", width - , face, this.FontSize, ref IsShowTip);
Console.WriteLine(IsShowTip);
ShowToolTip(IsShowTip);
}
}

如下图所示:width-10是为了提前10个宽度就要显示省略号:(减去10是为了解决 刚好文本长度填满整个文本时不显示省略号,临界值)

完整代码如下:

样式Xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TipPlugs"> <Style x:Key="XCloseButton" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Height" Value=""/>
<Setter Property="Width" Value=""/>
<Setter Property="ToolTip" Value="X"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Path x:Name="mPath" Data="M2.859125,1.4685 L1.4217499,2.889875 3.5625651,5.015809 1.4682621,7.1103131 2.8748757,8.5319866 4.9848079,6.4375335 7.111161,8.5628746 8.5181325,7.1407751 6.3768616,5.0154436 8.5341407,2.8744748 7.1115867,1.4523758 4.9855734,3.624328 z" Fill="White" Stretch="Fill" Margin="0.203" Stroke="#FFFFA1A1" Visibility="Collapsed"/>
<Path x:Name="nPath" Data="M2.859125,1.4685 L1.4217499,2.889875 3.5625651,5.015809 1.4682621,7.1103131 2.8748757,8.5319866 4.9848079,6.4375335 7.111161,8.5628746 8.5181325,7.1407751 6.3768616,5.0154436 8.5341407,2.8744748 7.1115867,1.4523758 4.9855734,3.624328 z" Fill="#4C666666" Stretch="Fill" Margin="0.203" Stroke="{x:Null}"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Visibility" TargetName="nPath" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="mPath" Value="Visible"/>
</Trigger>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--Tip-->
<Style TargetType="{x:Type local:TextBoxTip}">
<Setter Property="TopBrush" Value="{DynamicResource TextBoxTopBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource TextBoxBorder}"/>
<Setter Property="Background" Value="{DynamicResource TextBoxBackground}"/>
<Setter Property="XButtonVisibility" Value="Collapsed"/>
<Setter Property="Foreground" Value="LightGray"/>
<Setter Property="BorderThickness" Value=""/>
<Setter Property="Height" Value=""/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TextBoxTip}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Rectangle x:Name="OuterglowRect" Visibility="Collapsed"
Grid.ColumnSpan=""
RadiusX="" RadiusY="" Stroke="{DynamicResource OuterBlueBrush}" StrokeThickness="1.5" />
<Border x:Name="Bd" SnapsToDevicePixels="True"
CornerRadius="" Margin=""
Grid.ColumnSpan=""
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
<TextBox x:Name="PART_Text" Grid.Column=""
BorderThickness=""
Style="{x:Null}"
Padding="2,2"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
IsReadOnly="{Binding IsReadOnly,Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=TemplatedParent}}"
Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}">
<TextBox.Background>
<VisualBrush Stretch="None" AlignmentX="Left">
<VisualBrush.Transform>
<TranslateTransform X="" Y=""/>
</VisualBrush.Transform>
<VisualBrush.Visual>
<TextBlock x:Name="PART_EmptyText" Grid.Column="" Text="{TemplateBinding TooTipText}"
FontSize="" Visibility="Collapsed" Foreground="{TemplateBinding Foreground}"
Focusable="False"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
<Rectangle x:Name="glowRect" Margin="2 2 2 0"
RadiusX="" RadiusY="" Stroke="{x:Null}"
SnapsToDevicePixels="true" StrokeThickness=""
Grid.ColumnSpan=""
Fill="{TemplateBinding TopBrush}" Height="" VerticalAlignment="Top" > </Rectangle>
<Button Grid.Column=""
x:Name="Xbtn"
ToolTip="Clear"
Visibility="{TemplateBinding XButtonVisibility}"
VerticalAlignment="Center" Margin="7 0"
Command="{x:Static local:TextBoxTip.XButtonCommand}"
Style="{StaticResource XCloseButton}"/>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFocused,ElementName=PART_Text}" Value="False"/>
<Condition Binding="{Binding Path=Text,ElementName=PART_Text}" Value=""/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_EmptyText" Property="Visibility" Value="Visible"/>
</MultiDataTrigger> <!--<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsReadOnly}" Value="True"/>
<Condition Binding="{Binding Path=Text,ElementName=PART_Text}" Value=""/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_EmptyText" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>--> <Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter TargetName="OuterglowRect" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="{DynamicResource TextBoxBorderRead}"/>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource TextBoxBgRead}"/>
<Setter Property="Visibility" TargetName="glowRect" Value="Collapsed"/>
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Text,ElementName=PART_Text}" Value=""/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" TargetName="Xbtn" Value="Collapsed"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter> </Style> <!-- Sign TextBox-->
<local:TextBoxConverter x:Key="EmptyConverter"/>
<Style TargetType="{x:Type local:TextBoxSign}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value=""/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TextBoxSign}"> <Border x:Name="OutBorder" BorderThickness="" CornerRadius="" SnapsToDevicePixels="True">
<Border x:Name="InnerBorder"
CornerRadius="" SnapsToDevicePixels="True"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<TextBox x:Name="PART_Text" Grid.Column=""
BorderThickness=""
Style="{x:Null}"
FocusVisualStyle="{x:Null}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
IsReadOnly="{Binding IsReadOnly,Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=TemplatedParent}}"
Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}">
<TextBox.Background>
<VisualBrush Stretch="None" AlignmentX="Left">
<VisualBrush.Transform>
<TranslateTransform X="" Y=""/>
</VisualBrush.Transform>
<VisualBrush.Visual>
<TextBlock x:Name="PART_EmptyText" Grid.Column="" Text="{TemplateBinding TooTipText}"
FontSize="" Visibility="Collapsed" Foreground="{TemplateBinding Foreground}"
Focusable="False"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
<TextBox x:Name="txbTrimming"
Visibility="Hidden"
BorderThickness=""
Style="{x:Null}"
FocusVisualStyle="{x:Null}"
Background="Transparent"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Grid>
</Border>
</Border>
<ControlTemplate.Triggers> <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsFocused, ElementName=PART_Text}" Value="False"/>
<Condition Binding="{Binding Text, ElementName=PART_Text,Converter={StaticResource EmptyConverter}}" Value=""/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_EmptyText" Property="Visibility" Value="Visible"/>
<Setter TargetName="PART_Text" Property="Visibility" Value="Visible"/>
</MultiDataTrigger> <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsFocused, ElementName=PART_Text}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="OutBorder" Property="BorderBrush" Value="Gray"/>
<Setter Property="Background" Value="White" TargetName="InnerBorder"/>
<Setter Property="BorderBrush" Value="Transparent" TargetName="InnerBorder"/>
<Setter Property="BorderThickness" Value="" TargetName="InnerBorder"/>
</MultiDataTrigger> <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsFocused, ElementName=PART_Text}" Value="False"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="OutBorder" Property="BorderBrush" Value="#7F353535"/>
<Setter Property="BorderBrush" Value="#B2FFFFFF" TargetName="InnerBorder"/>
<Setter Property="Background" TargetName="InnerBorder">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
<GradientStop Offset="" Color="#A0FFFFFF"/>
<GradientStop Offset="0.1" Color="#70FFFFFF"/>
<GradientStop Offset="0.4" Color="#0CFFFFFF"/>
<GradientStop Offset="0.5" Color="#00FFFFFF"/>
<GradientStop Offset="0.6" Color="#0CFFFFFF"/>
<GradientStop Offset="0.9" Color="#70FFFFFF"/>
<GradientStop Offset="" Color="#A0FFFFFF"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

TextBoxTip Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 TipPlugs
{
/// <summary>
/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
///
/// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:TextBoxTip"
///
///
/// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:TextBoxTip;assembly=TextBoxTip"
///
/// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
/// 并重新生成以避免编译错误:
///
/// 在解决方案资源管理器中右击目标项目,然后依次单击
/// “添加引用”->“项目”->[浏览查找并选择此项目]
///
///
/// 步骤 2)
/// 继续操作并在 XAML 文件中使用控件。
///
/// <MyNamespace:TextBoxTip/>
///
/// </summary>
public class TextBoxTip : TextBox
{
static TextBoxTip()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxTip), new FrameworkPropertyMetadata(typeof(TextBoxTip)));
InitializeCommands();
} protected override void OnTextChanged(TextChangedEventArgs e)
{
string text = this.Text;
if (!string.IsNullOrEmpty(text) && IsShowXButton)
{
XButtonVisibility = Visibility.Visible;
}
//else if (string.IsNullOrEmpty(text))
//{
// XButtonVisibility = Visibility.Collapsed;
//}
base.OnTextChanged(e);
} /// <summary>
/// 提示文本,如:请输入用户名
/// </summary>
public string TooTipText
{
get { return (string)GetValue(TooTipTextProperty); }
set { SetValue(TooTipTextProperty, value); }
} // Using a DependencyProperty as the backing store for TootipText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TooTipTextProperty =
DependencyProperty.Register("TooTipText", typeof(string), typeof(TextBoxTip), new UIPropertyMetadata("", null)); /// <summary>
/// 三个像素描边颜色
/// </summary>
public Brush TopBrush
{
get { return (Brush)GetValue(TopBrushProperty); }
set { SetValue(TopBrushProperty, value); }
} // Using a DependencyProperty as the backing store for TopBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TopBrushProperty =
DependencyProperty.Register("TopBrush", typeof(Brush), typeof(TextBoxTip), new UIPropertyMetadata(null)); /// <summary>
/// 控制显示X按钮
/// </summary>
public Visibility XButtonVisibility
{
get { return (Visibility)GetValue(XButtonVisibilityProperty); }
set { SetValue(XButtonVisibilityProperty, value); }
} // Using a DependencyProperty as the backing store for XButtonVisibility. This enables animation, styling, binding, etc...
public static readonly DependencyProperty XButtonVisibilityProperty =
DependencyProperty.Register("XButtonVisibility", typeof(Visibility), typeof(TextBoxTip),
new UIPropertyMetadata(Visibility.Collapsed)); /// <summary>
/// 是否显示X按钮
/// </summary>
public bool IsShowXButton
{
get { return (bool)GetValue(IsShowXButtonProperty); }
set { SetValue(IsShowXButtonProperty, value); }
} // Using a DependencyProperty as the backing store for IsShowXButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsShowXButtonProperty =
DependencyProperty.Register("IsShowXButton", typeof(bool), typeof(TextBoxTip), new UIPropertyMetadata(false)); /// <summary>
/// Since we're using RoutedCommands for the increase/decrease commands, we need to
/// register them with the command manager so we can tie the events
/// to callbacks in the control.
/// </summary>
private static void InitializeCommands()
{
XButtonCommand = new RoutedCommand("XButtonCommand", typeof(TextBoxTip));
CommandManager.RegisterClassCommandBinding(typeof(TextBoxTip),
new CommandBinding(XButtonCommand, CloseButtonCommand));
} public static void CloseButtonCommand(Object sender, ExecutedRoutedEventArgs e)
{
TextBoxTip control = sender as TextBoxTip;
if (control != null)
{
control.Text = "";
}
} public static RoutedCommand XButtonCommand { set; get; }
}
}

TextBoxSign Code

using Commons;
using Commons.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 TipPlugs
{
/// <summary>
/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
///
/// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:TipPlugs"
///
///
/// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:TipPlugs;assembly=TipPlugs"
///
/// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
/// 并重新生成以避免编译错误:
///
/// 在解决方案资源管理器中右击目标项目,然后依次单击
/// “添加引用”->“项目”->[浏览查找并选择此项目]
///
///
/// 步骤 2)
/// 继续操作并在 XAML 文件中使用控件。
///
/// <MyNamespace:TextBoxSign/>
///
/// </summary>
public class TextBoxSign : TextBox
{
static TextBoxSign()
{ DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxSign), new FrameworkPropertyMetadata(typeof(TextBoxSign)));
} TextBox NormalTxt;
TextBox TrimmingTxt;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
NormalTxt = this.Template.FindName("PART_Text", this) as TextBox;
TrimmingTxt = this.Template.FindName("txbTrimming", this) as TextBox;
TrimmingTxt.GotFocus += new RoutedEventHandler(TrimmingTxt_GotFocus);
NormalTxt.LostFocus += new RoutedEventHandler(NormalTxt_LostFocus);
NormalTxt.GotFocus += new RoutedEventHandler(NormalTxt_GotFocus);
this.KeyUp += TextBoxSign_KeyUp;
} private void TextBoxSign_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
//FocusManager.SetFocusedElement(this, null);
//Keyboard.Focus(null);
NormalTxt_LostFocus(null, null);
}
} void NormalTxt_GotFocus(object sender, RoutedEventArgs e)
{
NormalIsFocus = true;
} protected override void OnTextChanged(TextChangedEventArgs e)
{
bool IsShow = false;
if (!string.IsNullOrEmpty(this.Text))
{
IsShow = true;
}
else
{
IsShow = false;
}
ShowToolTip(IsShow);
base.OnTextChanged(e);
} /// <summary>
/// 如何显示Tooltip文本
/// </summary>
/// <param name="isShow"></param>
private void ShowToolTip(bool isShow)
{
if (isShow)
{
this.ToolTip = this.Text;
}
else
{
this.ToolTip = null;
}
} void NormalTxt_LostFocus(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(this.Text))
{
double wd = this.ActualWidth;
ControlTrimming(wd);
}
NormalIsFocus = false;
} bool NormalIsFocus = false;
void TrimmingTxt_GotFocus(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(this.Text))
{
TrimmingTxt.Visibility = Visibility.Collapsed;
NormalTxt.Visibility = Visibility.Visible; }
NormalTxt.Focus(); } protected override Size ArrangeOverride(Size arrangeBounds)
{
Size size = base.ArrangeOverride(arrangeBounds);
if (NormalIsFocus == false)
{
ControlTrimming(arrangeBounds.Width);
}
return size;
}
private void ControlTrimming(double width)
{
if (!string.IsNullOrEmpty(this.Text))
{
NormalTxt.Visibility = Visibility.Hidden;
TrimmingTxt.Visibility = Visibility.Visible;
Typeface face = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch);
bool IsShowTip = false;
TrimmingTxt.Text = TrimmingHelper.Trim(Text, "...", "中回复哈市的范德萨发", width - , face, this.FontSize, ref IsShowTip);
Console.WriteLine(IsShowTip);
ShowToolTip(IsShowTip);
}
} /// <summary>
/// 提示文本,如:请输入用户名
/// </summary>
public string TooTipText
{
get { return (string)GetValue(TooTipTextProperty); }
set { SetValue(TooTipTextProperty, value); }
} // Using a DependencyProperty as the backing store for TootipText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TooTipTextProperty =
DependencyProperty.Register("TooTipText", typeof(string), typeof(TextBoxSign), new UIPropertyMetadata("", null));
} class TextBoxConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ return "";
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

TrimmingHelper Code

/***********************************************************************
* Copyright(c) 2016-2050 ligl
* CLR 版本: 4.0.30319.42000
* 文 件 名:TrimmingHelper
* 创 建 人:ligl
* 创建日期:2016/7/14 21:05:16
* 修 改 人:ligl
* 修改日期:
* 备注描述:
************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Media; namespace Commons.Helper
{
/// <summary>
/// 计算长度是否超出文本宽度的帮助类
/// </summary>
public class TrimmingHelper
{ /// <summary>
///
/// </summary>
/// <param name="source">原始文本</param>
/// <param name="suffix">省略文本符号</param>
/// <param name="endNoTrimSource">追加省略号后面的文本,source+endNoTrimSource总体长度计算省略号</param>
/// <param name="width">文本长度</param>
/// <param name="face">字体类</param>
/// <param name="fontsize">字体大小</param>
/// <param name="ShowTip">True标示截取了文本</param>
/// <returns></returns>
public static string Trim(string source, string suffix, string endNoTrimSource, double width, Typeface face, double fontsize, ref bool ShowTip)
{ if (face != null)
{
//real display max width.
double realWidth = width; //try to get GlyphTypeface.
GlyphTypeface glyphTypeface;
face.TryGetGlyphTypeface(out glyphTypeface); if (glyphTypeface != null)
{
//calculate end string 's display width.
if (!string.IsNullOrEmpty(endNoTrimSource))
{
double notrimWidth = ;
foreach (char c in endNoTrimSource)
{
ushort w;
glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w);
notrimWidth += glyphTypeface.AdvanceWidths[w] * fontsize;
} realWidth = width - notrimWidth;
} //calculate source 's screen width
double sourceWidth = ;
if (!string.IsNullOrEmpty(source))
{
foreach (char c in source)
{
ushort w;
glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w);
sourceWidth += glyphTypeface.AdvanceWidths[w] * fontsize;
}
} //don't need to trim.
if (sourceWidth <= realWidth) return source + endNoTrimSource; //calculate suffix's display width
double suffixWidth = ;
if (!string.IsNullOrEmpty(suffix))
{
foreach (char c in suffix)
{
ushort w;
glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w);
suffixWidth += glyphTypeface.AdvanceWidths[w] * fontsize;
}
} realWidth = realWidth - suffixWidth; if (realWidth > )
{
sourceWidth = ;
string trimStr = string.Empty;
foreach (char c in source)
{
ushort w;
glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); double cWidth = glyphTypeface.AdvanceWidths[w] * fontsize; if ((sourceWidth + cWidth) > realWidth)
{
ShowTip = true;
return trimStr + suffix + endNoTrimSource;
}
trimStr += c;
sourceWidth += cWidth;
}
}
else
{
ShowTip = true;
if (width > suffixWidth) return suffix;
else return "..."; }
}
}
ShowTip = false;
return source + endNoTrimSource;
}
}
}

使用方式:

<UserControl x:Class="TipPlugs.UserControlTip"
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:TipPlugs"
mc:Ignorable="d"
d:DesignHeight="" d:DesignWidth="">
<UserControl.Resources>
<!--ffffff %透明 --->
<SolidColorBrush x:Key="Brush61" Color="#99FFFFFF"/> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" x:Key="TopBdBrush">
<GradientStop Color="#5B808080" Offset=""/>
<GradientStop Color="#19808080" Offset=""/>
</LinearGradientBrush> <SolidColorBrush x:Key="BdBrush" Color="#6643484B"></SolidColorBrush>
</UserControl.Resources>
<Grid>
<StackPanel>
<local:TextBoxTip
VerticalContentAlignment="Top"
Background="{StaticResource Brush61}"
BorderBrush="{StaticResource BdBrush}"
TopBrush="{StaticResource TopBdBrush}"
Foreground="#FF7F7F7F"
IsShowXButton="True"
Width=""
HorizontalAlignment="Left"
TooTipText="输入关键字,回车进行搜索"
x:Name="txtSearch"></local:TextBoxTip>
<local:TextBoxSign x:Name="txbSignatrue" Text="{Binding Signature,Mode=TwoWay}"
HorizontalAlignment="Left"
TooTipText="编辑个性签名" Height="" Width=""
Margin="0,2"/>
</StackPanel> </Grid>
</UserControl>

源代码下载

TextBox自定义控件的更多相关文章

  1. WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要是对文本 ...

  2. WinForm程序中的类TextBox的自定义控件, 添加失去焦点的功能

    原理: 一.在控件的后台代码中, 添加布尔类型的属性CanFocus 二.在控件的构造函数中, 注册Enter事件的处理方法. 并在处理方法中,根据CanFocus属性的值来决定是否可以丢失焦点, 如 ...

  3. 【转】WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括: 基本文 ...

  4. WinForm自定义控件–TextBox扩展

      一.简单回顾 在前两节中,对Panel和GroupBox控件进行了相关的扩展应用,主要都是设置控件的边框以及边框颜色等.本节,继续对WinForm现有的控件TextBox进行扩展,来满足实际开发中 ...

  5. 工作记录--WPF自定义控件,实现一个可设置编辑模式的TextBox

    原文:工作记录--WPF自定义控件,实现一个可设置编辑模式的TextBox 1. 背景 因为最近在使用wpf开发桌面端应用,在查看页面需要把TextBox和Combox等控件设置为只读的.原本是个很简 ...

  6. (八十九)c#Winform自定义控件-自定义滚动条(treeview、panel、datagridview、listbox、listview、textbox)

    官网 http://www.hzhcontrols.com/ 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kw ...

  7. 自定义控件之 TextBox

    //textbox typevar boxType = { WaterMarkBox: 0, ValidateBox: 1, SearchBox: 2}var textBoxObj = functio ...

  8. WPF自定义控件(二)——TextBox

    和之前一样,先来看看效果: 这个TextBox可设置水印,可设置必填和正则表达式验证. 验证?没错,就是验证! 就是在输入完成后,控件一旦失去焦点就会自动验证!会根据我开放出来的“是否可以为空”属性进 ...

  9. C# Winfrom 自定义控件——带图片的TextBox

    效果: 描述: 本来是想用GDI在左边画图片上去的,文本是居中对齐,如果文本是左对齐,文本会把图片遮住控件长这样: 但这样做,输入框在获取焦点时候,会把图片挡住就像这样: 输入完成之后图片就会显示完整 ...

随机推荐

  1. C#语言基础——结构体和枚举类型

    结构体和枚举类型 一.结构体(struct) 结构类型是用户自己定义的一种类型,它是由其他类型组合而成的,可包含构造函数.常数.字段.方法.属性.索引器.运算符.事件和嵌套类型的值类型.结构在几个重要 ...

  2. mysql数据校验之字符集问题

    场景:主库DB:utf8字符集备库DB:gbk字符集 需求:校验主备数据是否一致,并且修复 校验过程:设置主库连接为utf8,设置备库连接为gbk,分别进行查询,将返回的的结果集按记录逐字段比较. 显 ...

  3. User Word Automation Services and Open XML SDK to generate word files in SharePoint2010

    SharePoint 2010 has established a new service called "Word Automation Services" to operate ...

  4. What Need To Do when A Node down!

    就以pdsp node3 down了为例,如下 ==========================START===================================== The Who ...

  5. Oracle Latch的学习【原创】

    Latch详解 - MaxChou 本文以学习为目的,大部分内容来自网络转载. 什么是Latch 串行化 数据库系统本身是一个多用户并发处理系统,在同一个时间点上,可能会有多个用户同时操作数据库.多个 ...

  6. openstack-kilo--issue(九) heat stacks topology中图形无法正常显示

    ======声明======= 欢迎转载:转载请注明出处 http://www.cnblogs.com/horizonli/p/6186581.html ==========环境=========== ...

  7. 支付宝APP支付开发- IOException : DER input, Integer tag error

    支付宝APP支付Java开发报错: 1 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: I ...

  8. Linux软件安装-RPM安装

    RPM是RPM Package Manager(RPM软件包管理器)的缩写,这一文件格式名称虽然打上了RedHat的标志,但是其原始设计理念是开放式的,现在包括OpenLinux.         S ...

  9. 手机打开PDF文档中文英文支持(乱码问题)解决攻略

    电子书的优点很多,随时随地阅读,无论白天黑夜走路坐车都能阅读:想确认一下某句话是不是这本书里的,搜索一下就可以知道:搬家也不用发愁,几万本书带在身上,依然轻松步行.我买了一台平板主要动因就是为了看书, ...

  10. Serializable

    import java.io.*;    public class  Box implements Serializable   {       private int width;       pr ...