TextBox自定义控件

时间:2023-03-10 07:12:33
TextBox自定义控件

首先来一发图:

TextBox自定义控件

今天主要说的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是为了解决 刚好文本长度填满整个文本时不显示省略号,临界值)

TextBox自定义控件

完整代码如下:

TextBox自定义控件

样式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>

源代码下载