效果:
Style:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:ImageButtonTest01.Control"
xmlns:converter="clr-namespace:ImageButtonTest01.Control.Converter">
<converter:ImageTextBoxMarginLeftConverter x:Key="ITBMLC"/>
<converter:PlaceholderFontSizeConverter x:Key="PHFSC"/>
<SolidColorBrush x:Key="ImageTextBox.Static.BorderBrush" Color="#FF909090"/>
<SolidColorBrush x:Key="ImageTextBox.Focused.BorderBrush" Color="#FF007ACC"/>
<SolidColorBrush x:Key="ImageTextBox.MouseOver.BorderBrush" Color="#FF1E1E1E"/>
<Style TargetType="{x:Type ctrls:ImageTextBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="{StaticResource ImageTextBox.Focused.BorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="CaretBrush" Value="Black"/>
<Setter Property="Opacity" Value="1"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctrls:ImageTextBox}">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ITBMLC}}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image x:Name="PART_ContentIdentity" Grid.Column="1" Margin="0" Stretch="Uniform"
Width="{Binding LeftImageWidth, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding LeftImageWidth, RelativeSource={RelativeSource TemplatedParent}}"
Source="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<ScrollViewer x:Name="PART_ContentHost" Grid.Column="2" IsTabStop="False" Margin="2,0,2,0"
Focusable="false" Background="Transparent" SnapsToDevicePixels="True"
HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalContentAlignment="Left"/>
<TextBlock x:Name="PART_PlaceHolder" Grid.Column="2" IsHitTestVisible="False" Margin="3,0,3,0"
HorizontalAlignment="Left" VerticalAlignment="Center"
SnapsToDevicePixels="True"
Visibility="Collapsed" Opacity="0.6"
TextAlignment="{TemplateBinding TextAlignment}"
Text="{Binding Path=PlaceHolder, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource PHFSC}}"/>
<ctrls:ImageButton x:Name="PART_ClearTextButton" Grid.Column="3" Margin="2" IsTabStop="False"
FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
Content="" FontSize="20"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Style="{StaticResource ImageButtonTransparent}"/>
<ctrls:ImageButton x:Name="PART_ExtendIconFontButton" Grid.Column="4" FontSize="20"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
Content="{Binding ExtendIconFontText, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ImageButtonTransparent}"
Command="{Binding ExtendButtonCommand, RelativeSource={RelativeSource TemplatedParent}}"
CommandParameter="{Binding ExtendButtonCommandParameter, RelativeSource={RelativeSource TemplatedParent}}"
CommandTarget="{Binding ExtendButtonCommandTarget, RelativeSource={RelativeSource TemplatedParent}}"/>
<ctrls:ImageButton x:Name="PART_ExtendImageButton" Grid.Column="5"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
NormalImage="{Binding ExtendNormalImage, RelativeSource={RelativeSource TemplatedParent}}"
HoverImage="{Binding ExtendHoverImage, RelativeSource={RelativeSource TemplatedParent}}"
PressedImage="{Binding ExtendPressedImage, RelativeSource={RelativeSource TemplatedParent}}"
DisabledImage="{Binding ExtendDisabledImage, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ImageButtonTransparent}"
Command="{Binding ExtendButtonCommand, RelativeSource={RelativeSource TemplatedParent}}"
CommandParameter="{Binding ExtendButtonCommandParameter, RelativeSource={RelativeSource TemplatedParent}}"
CommandTarget="{Binding ExtendButtonCommandTarget, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=ExtendNormalImage, RelativeSource={RelativeSource Mode=Self}}" Value="{x:Null}">
<Setter TargetName="PART_ExtendImageButton" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ExtendIconFontText, RelativeSource={RelativeSource Mode=Self}}" Value="">
<Setter TargetName="PART_ExtendIconFontButton" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
<Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
<Setter TargetName="PART_ClearTextButton" Property="IsEnabled" Value="False"/>
<Setter TargetName="PART_ExtendIconFontButton" Property="IsEnabled" Value="False"/>
<Setter TargetName="PART_ExtendImageButton" Property="IsEnabled" Value="False"/>
</DataTrigger>
<Trigger Property="IsFocused" Value="False">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource ImageTextBox.Static.BorderBrush}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource ImageTextBox.MouseOver.BorderBrush}"/>
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter TargetName="PART_ClearTextButton" Property="IsEnabled" Value="False"/>
<Setter Property="Opacity" Value="0.6" TargetName="border" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.5" TargetName="border" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
C#
ImageTextBox.CS
public class ImageTextBox : TextBox
{
private ImageButton mClearTextButton = null;
private ImageButton mExtendIconFontButton = null;
private ImageButton mExtendImageButton = null;
static ImageTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageTextBox), new FrameworkPropertyMetadata(typeof(ImageTextBox)));
}
public ImageTextBox()
{
}
public override void OnApplyTemplate()
{
mClearTextButton = GetTemplateChild("PART_ClearTextButton") as ImageButton;
if (null != mClearTextButton)
{
mClearTextButton.Click += OnClearTextClick;
}
mExtendIconFontButton = GetTemplateChild("PART_ExtendIconFontButton") as ImageButton;
if (null != mExtendIconFontButton)
{
mExtendIconFontButton.Click += ExtendButtonClick;
}
mExtendImageButton = GetTemplateChild("PART_ExtendImageButton") as ImageButton;
if (null != mExtendIconFontButton)
{
mExtendImageButton.Click += ExtendButtonClick;
}
base.OnApplyTemplate();
}
private void ExtendButtonClick(object sender, RoutedEventArgs e)
{
RoutedEventArgs re = new RoutedEventArgs(ImageTextBox.ExtendClickEvent, this);
RaiseEvent(re);
}
private void OnClearTextClick(object sender, RoutedEventArgs e)
{
if (sender is ImageButton)
{
Text = "";
}
}
public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(nameof(Image), typeof(ImageSource), typeof(ImageTextBox),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));
public ImageSource Image
{
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
public static readonly DependencyProperty ExtendNormalImageProperty = DependencyProperty.Register(nameof(ExtendNormalImage), typeof(ImageSource), typeof(ImageTextBox),
new FrameworkPropertyMetadata(null));
public ImageSource ExtendNormalImage
{
get { return (ImageSource)GetValue(ExtendNormalImageProperty); }
set { SetValue(ExtendNormalImageProperty, value); }
}
public static readonly DependencyProperty ExtendHoverImageProperty = DependencyProperty.Register(nameof(ExtendHoverImage), typeof(ImageSource), typeof(ImageTextBox),
new FrameworkPropertyMetadata(null));
public ImageSource ExtendHoverImage
{
get { return (ImageSource)GetValue(ExtendHoverImageProperty); }
set { SetValue(ExtendHoverImageProperty, value); }
}
public static readonly DependencyProperty ExtendPressedImageProperty = DependencyProperty.Register(nameof(ExtendPressedImage), typeof(ImageSource), typeof(ImageTextBox),
new FrameworkPropertyMetadata(null));
public ImageSource ExtendPressedImage
{
get { return (ImageSource)GetValue(ExtendPressedImageProperty); }
set { SetValue(ExtendPressedImageProperty, value); }
}
public static readonly DependencyProperty ExtendDisabledImageProperty = DependencyProperty.Register(nameof(ExtendDisabledImage), typeof(ImageSource), typeof(ImageTextBox),
new FrameworkPropertyMetadata(null));
public ImageSource ExtendDisabledImage
{
get { return (ImageSource)GetValue(ExtendDisabledImageProperty); }
set { SetValue(ExtendDisabledImageProperty, value); }
}
public static readonly DependencyProperty PlaceHolderProperty = DependencyProperty.Register(nameof(PlaceHolder), typeof(string),
typeof(ImageTextBox), new PropertyMetadata(""));
public string PlaceHolder
{
get { return (string)GetValue(PlaceHolderProperty); }
set { SetValue(PlaceHolderProperty, value); }
}
public static readonly DependencyProperty ExtendIconFontTextProperty = DependencyProperty.Register(nameof(ExtendIconFontText), typeof(string),
typeof(ImageTextBox), new PropertyMetadata(""));
public string ExtendIconFontText
{
get { return (string)GetValue(ExtendIconFontTextProperty); }
set { SetValue(ExtendIconFontTextProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius),
typeof(ImageTextBox), new PropertyMetadata(new CornerRadius(0,0,0,0)));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty LeftImageWidthProperty = DependencyProperty.Register(nameof(LeftImageWidth), typeof(double),
typeof(ImageTextBox), new PropertyMetadata(0.0));
public double LeftImageWidth
{
get { return (double)GetValue(LeftImageWidthProperty); }
set { SetValue(LeftImageWidthProperty, value); }
}
private static void ImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ImageTextBox itb = sender as ImageTextBox;
ImageSource image = e.NewValue as ImageSource;
itb.SetValue(LeftImageWidthProperty, image.Width);
}
public static readonly RoutedEvent ExtendClickEvent = EventManager.RegisterRoutedEvent(nameof(ExtendClick), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(ImageTextBox));
public event RoutedEventHandler ExtendClick
{
add { AddHandler(ExtendClickEvent, value); }
remove { RemoveHandler(ExtendClickEvent, value); }
}
public static DependencyProperty ExtendButtonCommandProperty = DependencyProperty.Register(nameof(ExtendButtonCommand), typeof(ICommand), typeof(ImageTextBox));
public ICommand ExtendButtonCommand
{
get { return (ICommand)GetValue(ExtendButtonCommandProperty); }
set { SetValue(ExtendButtonCommandProperty, value); }
}
public static readonly DependencyProperty ExtendButtonCommandParameterProperty =
DependencyProperty.Register(nameof(ExtendButtonCommandParameter), typeof(object), typeof(ImageTextBox), new UIPropertyMetadata(null));
public object ExtendButtonCommandParameter
{
get { return (object)GetValue(ExtendButtonCommandParameterProperty); }
set { SetValue(ExtendButtonCommandParameterProperty, value); }
}
public static readonly DependencyProperty ExtendButtonCommandTargetProperty =
DependencyProperty.Register(nameof(ExtendButtonCommandTarget), typeof(IInputElement), typeof(ImageTextBox), new UIPropertyMetadata(null));
public IInputElement ExtendButtonCommandTarget
{
get { return (IInputElement)GetValue(ExtendButtonCommandTargetProperty); }
set { SetValue(ExtendButtonCommandTargetProperty, value); }
}
}
转换器ImageTextBoxMarginLeftConverter.cs
public class ImageTextBoxMarginLeftConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
{
double v = (double)value;
return v * 3.0 / 5.0;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
使用:
<StackPanel Orientation="Vertical" Grid.Row="1">
<control:ImageTextBox x:Name="tbUserName" Width="200" Height="50" FontSize="30" Margin="5"
CornerRadius="12"
PlaceHolder="请输入用户名"
ExtendIconFontText=""
ExtendNormalImage="Resources/Images/MS.png"
ExtendHoverImage="Resources/Images/MS.png"
ExtendPressedImage="Resources/Images/MS.png"
ExtendDisabledImage="Resources/Images/MS.png"
Text="{Binding InputText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ExtendButtonCommand="{Binding BottonCommand}" ExtendButtonCommandParameter="button1 Click"/>
<control:ImageTextBox x:Name="tbUserName1" Width="200" Height="50" Margin="5"
ExtendIconFontText=""
CornerRadius="20" FontSize="20" Background="YellowGreen"
PlaceHolder="请输入用户名"/>
<control:ImageTextBox x:Name="tbUserName2" Width="200" Height="50" Margin="5"
ExtendNormalImage="Resources/Images/MS.png"
ExtendHoverImage="Resources/Images/MS.png"
ExtendPressedImage="Resources/Images/MS.png"
ExtendDisabledImage="Resources/Images/MS.png"
PlaceHolder="请输入用户名"
Image="Resources/Images/logo.png"/>
<control:ImageTextBox x:Name="tbUserName3" Width="200" Height="50" Margin="5"
PlaceHolder="请输入用户名" CornerRadius="20" IsEnabled="True"
Image="Resources/Images/logo.png"/>
<control:ImageTextBox x:Name="tbUserName4" Width="200" Height="50" Margin="5"
PlaceHolder="请输入用户名" CornerRadius="20" IsEnabled="False"
Image="Resources/Images/logo.png"/>
<TextBox Width="200" Height="30" Margin="5"/>
</StackPanel>
<!--校验错误提示模板-->
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="3" BorderBrush="Red" BorderThickness="1">
<StackPanel Orientation="Vertical">
<AdornedElementPlaceholder x:Name="Adorned"/>
<TextBlock Width="{TemplateBinding Width}" Foreground="Red" FontSize="16">
<TextBlock.Text>
<Binding ElementName="Adorned" Path="AdornedElement.(Validation.Errors)[0].ErrorContent"/>
</TextBlock.Text>
<TextBlock.Effect>
<DropShadowEffect Opacity="0.6" ShadowDepth="3" Color="Black"/>
</TextBlock.Effect>
</TextBlock>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>