我正在寻找一种将占位符文本添加到文本框的方法,就像使用 html5 中的文本框一样。
即如果文本框没有文本,则添加文本Enter some text here
,当用户单击它时,占位符文本消失并允许用户输入自己的文本,如果文本框失去焦点并且仍然没有文本,则占位符是添加回文本框。
我正在寻找一种将占位符文本添加到文本框的方法,就像使用 html5 中的文本框一样。
即如果文本框没有文本,则添加文本Enter some text here
,当用户单击它时,占位符文本消失并允许用户输入自己的文本,如果文本框失去焦点并且仍然没有文本,则占位符是添加回文本框。
那不就是这样吗:
Textbox myTxtbx = new Textbox();
myTxtbx.Text = "Enter text here...";
myTxtbx.GotFocus += GotFocus.EventHandle(RemoveText);
myTxtbx.LostFocus += LostFocus.EventHandle(AddText);
public void RemoveText(object sender, EventArgs e)
{
if (myTxtbx.Text == "Enter text here...")
{
myTxtbx.Text = "";
}
}
public void AddText(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(myTxtbx.Text))
myTxtbx.Text = "Enter text here...";
}
那只是伪代码,但概念就在那里。
您可以使用它,它对我有用,并且是非常简单的解决方案。
<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Panel.ZIndex="2" />
<TextBox Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
用法:
<TextBox Style="{StaticResource placeHolder}" Tag="Name of customer" Width="150" Height="24"/>
除了处理焦点进入和焦点离开事件来设置和删除占位符文本之外,还可以使用 Windows SendMessage 函数将 EM_SETCUEBANNER
消息发送到我们的文本框来为我们完成工作。
这可以通过两个简单的步骤来完成。首先,我们需要公开 WindowsSendMessage
功能。
private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);
然后只需使用我们的文本框的句柄、EM_SETCUEBANNER 的值和我们要设置的文本来调用该方法。
SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "Username");
SendMessage(textBox2.Handle, EM_SETCUEBANNER, 0, "Password");
将此类添加到您的项目并构建您的解决方案。单击 Visual Studio 上的工具箱,您将看到一个名为 PlaceholderTextBox 的新文本框组件。删除表单设计上的当前文本框并替换为 PlaceHolderTextBox。
PlaceHolderTextBox 有一个属性 PlaceHolderText。设置您想要的任何文本并度过美好的一天:)
public class PlaceHolderTextBox : TextBox
{
bool isPlaceHolder = true;
string _placeHolderText;
public string PlaceHolderText
{
get { return _placeHolderText; }
set
{
_placeHolderText = value;
setPlaceholder();
}
}
public new string Text
{
get => isPlaceHolder ? string.Empty : base.Text;
set => base.Text = value;
}
//when the control loses focus, the placeholder is shown
private void setPlaceholder()
{
if (string.IsNullOrEmpty(base.Text))
{
base.Text = PlaceHolderText;
this.ForeColor = Color.Gray;
this.Font = new Font(this.Font, FontStyle.Italic);
isPlaceHolder = true;
}
}
//when the control is focused, the placeholder is removed
private void removePlaceHolder()
{
if (isPlaceHolder)
{
base.Text = "";
this.ForeColor = System.Drawing.SystemColors.WindowText;
this.Font = new Font(this.Font, FontStyle.Regular);
isPlaceHolder = false;
}
}
public PlaceHolderTextBox()
{
GotFocus += removePlaceHolder;
LostFocus += setPlaceholder;
}
private void setPlaceholder(object sender, EventArgs e)
{
setPlaceholder();
}
private void removePlaceHolder(object sender, EventArgs e)
{
removePlaceHolder();
}
}
这不是我的代码,但我经常使用它,而且效果很好……仅限 XAML
<TextBox x:Name="Textbox" Height="23" Margin="0,17,18.8,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" HorizontalAlignment="Right" ></TextBox>
<TextBlock x:Name="Placeholder" IsHitTestVisible="False" TextWrapping="Wrap" Text="Placeholder Text" VerticalAlignment="Top" Margin="0,20,298.8,0" Foreground="DarkGray" HorizontalAlignment="Right" Width="214">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=Textbox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
救援的附加属性:
public static class TextboxExtensions
{
public static readonly DependencyProperty PlaceholderProperty =
DependencyProperty.RegisterAttached(
"Placeholder",
typeof(string),
typeof(TextboxExtensions),
new PropertyMetadata(default(string), propertyChangedCallback: PlaceholderChanged)
);
private static void PlaceholderChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var tb = dependencyObject as TextBox;
if (tb == null)
return;
tb.LostFocus -= OnLostFocus;
tb.GotFocus -= OnGotFocus;
if (args.NewValue != null)
{
tb.GotFocus += OnGotFocus;
tb.LostFocus += OnLostFocus;
}
SetPlaceholder(dependencyObject, args.NewValue as string);
if (!tb.IsFocused)
ShowPlaceholder(tb);
}
private static void OnLostFocus(object sender, RoutedEventArgs routedEventArgs)
{
ShowPlaceholder(sender as TextBox);
}
private static void OnGotFocus(object sender, RoutedEventArgs routedEventArgs)
{
HidePlaceholder(sender as TextBox);
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static void SetPlaceholder(DependencyObject element, string value)
{
element.SetValue(PlaceholderProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static string GetPlaceholder(DependencyObject element)
{
return (string)element.GetValue(PlaceholderProperty);
}
private static void ShowPlaceholder(TextBox textBox)
{
if (string.IsNullOrWhiteSpace(textBox.Text))
{
textBox.Text = GetPlaceholder(textBox);
}
}
private static void HidePlaceholder(TextBox textBox)
{
string placeholderText = GetPlaceholder(textBox);
if (textBox.Text == placeholderText)
textBox.Text = string.Empty;
}
}
用法:
<TextBox Text="hi" local:TextboxExtensions.Placeholder="Hello there"></TextBox>
虽然使用EM_SETCUEBANNER
消息可能是最简单的,但我不喜欢的一件事是当控件获得焦点时占位符文本会消失。当我填写表格时,这是我的一个小烦恼。我必须单击它才能记住该字段的用途。
因此,这是 WinForms 的另一种解决方案。它覆盖Label
在控件的顶部,仅当用户开始键入时它才会消失。
这当然不是防弹的。它接受 any Control
,但我只用TextBox
. 它可能需要修改才能与某些控件一起使用。如果您需要在特定情况下对其进行一些修改,该方法将返回Label
控件,但这可能永远不需要。
像这样使用它:
SetPlaceholder(txtSearch, "Type what you're searching for");
这是方法:
/// <summary>
/// Sets placeholder text on a control (may not work for some controls)
/// </summary>
/// <param name="control">The control to set the placeholder on</param>
/// <param name="text">The text to display as the placeholder</param>
/// <returns>The newly-created placeholder Label</returns>
public static Label SetPlaceholder(Control control, string text) {
var placeholder = new Label {
Text = text,
Font = control.Font,
ForeColor = Color.Gray,
BackColor = Color.Transparent,
Cursor = Cursors.IBeam,
Margin = Padding.Empty,
//get rid of the left margin that all labels have
FlatStyle = FlatStyle.System,
AutoSize = false,
//Leave 1px on the left so we can see the blinking cursor
Size = new Size(control.Size.Width - 1, control.Size.Height),
Location = new Point(control.Location.X + 1, control.Location.Y)
};
//when clicking on the label, pass focus to the control
placeholder.Click += (sender, args) => { control.Focus(); };
//disappear when the user starts typing
control.TextChanged += (sender, args) => {
placeholder.Visible = string.IsNullOrEmpty(control.Text);
};
//stay the same size/location as the control
EventHandler updateSize = (sender, args) => {
placeholder.Location = new Point(control.Location.X + 1, control.Location.Y);
placeholder.Size = new Size(control.Size.Width - 1, control.Size.Height);
};
control.SizeChanged += updateSize;
control.LocationChanged += updateSize;
control.Parent.Controls.Add(placeholder);
placeholder.BringToFront();
return placeholder;
}
基于 ExceptionLimeCat 的回答,改进:
Color farbe;
string ph = "Placeholder-Text";
private void Form1_Load(object sender, EventArgs e)
{
farbe = myTxtbx.ForeColor;
myTxtbx.GotFocus += RemoveText;
myTxtbx.LostFocus += AddText;
myTxtbx.Text = ph;
}
public void RemoveText(object sender, EventArgs e)
{
myTxtbx.ForeColor = farbe;
if (myTxtbx.Text == ph)
myTxtbx.Text = "";
}
public void AddText(object sender, EventArgs e)
{
if (String.IsNullOrWhiteSpace(myTxtbx.Text))
{
myTxtbx.ForeColor = Color.Gray;
myTxtbx.Text = ph;
}
}
这意味着您有一个按钮,可让您执行操作,例如登录或其他操作。在执行操作之前,请检查文本框是否已填写。如果没有,它将替换文本
private void button_Click(object sender, EventArgs e)
{
string textBoxText = textBox.Text;
if (String.IsNullOrWhiteSpace(textBoxText))
{
textBox.Text = "Fill in the textbox";
}
}
private void textBox_Enter(object sender, EventArgs e)
{
TextBox currentTextbox = sender as TextBox;
if (currentTextbox.Text == "Fill in the textbox")
{
currentTextbox.Text = "";
}
}
这有点俗气,但是检查文本以获取您提供的值是我能做的最好的 atm,而不擅长 c# 以获得更好的解决方案。
您可以获取默认值Template
,通过覆盖 a 对其进行修改TextBlock
,并使用 aStyle
添加以正确状态隐藏和显示它的触发器。
我知道这是一个旧线程,但 .NET Core 和 .NET 5.0 已经实现了该TextBox.PlaceholderText
属性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace App_name
{
public class CustomTextBox : TextBox
{
private string Text_ = "";
public CustomTextBox() : base()
{}
public string setHint
{
get { return Text_; }
set { Text_ = value; }
}
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
if (Text_.Equals(this.Text))
this.Clear();
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
if (String.IsNullOrWhiteSpace(this.Text))
this.Text = Text_;
}
}
}
> xmlns:local="clr-namespace:app_name"
> <local:CustomTextBox
> x:Name="id_number_txt"
> Width="240px"
> Height="auto"/>
这是 texbox 的扩展方法。只需以编程方式添加占位符文本:
myTextBox.AddPlaceholderText("Hello World!");
扩展方法:
public static void AddPlaceholderText(this TextBox textBox, string placeholderText)
{
if (string.IsNullOrWhiteSpace(textBox.Text))
textBox.Text = placeholderText;
textBox.SetResourceReference(Control.ForegroundProperty,
textBox.Text != placeholderText
? "SystemControlForegroundBaseHighBrush"
: "SystemControlForegroundBaseMediumBrush");
var ignoreSelectionChanged = false;
textBox.SelectionChanged += (sender, args) =>
{
if (ignoreSelectionChanged) { ignoreSelectionChanged = false; return; }
if (textBox.Text != placeholderText) return;
ignoreSelectionChanged = true;
textBox.Select(0, 0);
};
var lastText = textBox.Text;
var ignoreTextChanged = false;
textBox.TextChanged += (sender, args) =>
{
if (ignoreTextChanged) { ignoreTextChanged = false; return; }
if (string.IsNullOrWhiteSpace(textBox.Text))
{
ignoreTextChanged = true;
textBox.Text = placeholderText;
textBox.Select(0, 0);
}
else if (lastText == placeholderText)
{
ignoreTextChanged = true;
textBox.Text = textBox.Text.Substring(0, 1);
textBox.Select(1, 0);
}
textBox.SetResourceReference(Control.ForegroundProperty,
textBox.Text != placeholderText
? "SystemControlForegroundBaseHighBrush"
: "SystemControlForegroundBaseMediumBrush");
lastText = textBox.Text;
};
}
快乐编码,BierDav
在这里,我提出了受@Kemal Karadag 启发的解决方案。
我注意到这里发布的每个解决方案都依赖于焦点,
虽然我希望我的占位符是 Google Chrome 中标准 HTML 占位符的精确克隆。
当框聚焦时,而不是隐藏/显示占位符,
我根据框的文本长度隐藏/显示占位符:
如果框为空,则显示占位符,如果您在框中键入,则占位符消失。
由于它继承自标准文本框,因此您可以在工具箱中找到它!
using System;
using System.Drawing;
using System.Windows.Forms;
public class PlaceHolderTextBox : TextBox
{
private bool isPlaceHolder = true;
private string placeHolderText;
public string PlaceHolderText
{
get { return placeHolderText; }
set
{
placeHolderText = value;
SetPlaceholder();
}
}
public PlaceHolderTextBox()
{
TextChanged += OnTextChanged;
}
private void SetPlaceholder()
{
if (!isPlaceHolder)
{
this.Text = placeHolderText;
this.ForeColor = Color.Gray;
isPlaceHolder = true;
}
}
private void RemovePlaceHolder()
{
if (isPlaceHolder)
{
this.Text = this.Text[0].ToString(); // Remove placeHolder text, but keep the character we just entered
this.Select(1, 0); // Place the caret after the character we just entered
this.ForeColor = System.Drawing.SystemColors.WindowText;
isPlaceHolder = false;
}
}
private void OnTextChanged(object sender, EventArgs e)
{
if (this.Text.Length == 0)
{
SetPlaceholder();
}
else
{
RemovePlaceHolder();
}
}
}
我想出了一种对我有用的方法,但这只是因为我愿意使用文本框名称作为占位符。见下文。
public TextBox employee = new TextBox();
private void InitializeHomeComponent()
{
//
//employee
//
this.employee.Name = "Caller Name";
this.employee.Text = "Caller Name";
this.employee.BackColor = System.Drawing.SystemColors.InactiveBorder;
this.employee.Location = new System.Drawing.Point(5, 160);
this.employee.Size = new System.Drawing.Size(190, 30);
this.employee.TabStop = false;
this.Controls.Add(employee);
// I loop through all of my textboxes giving them the same function
foreach (Control C in this.Controls)
{
if (C.GetType() == typeof(System.Windows.Forms.TextBox))
{
C.GotFocus += g_GotFocus;
C.LostFocus += g_LostFocus;
}
}
}
private void g_GotFocus(object sender, EventArgs e)
{
var tbox = sender as TextBox;
tbox.Text = "";
}
private void g_LostFocus(object sender, EventArgs e)
{
var tbox = sender as TextBox;
if (tbox.Text == "")
{
tbox.Text = tbox.Name;
}
}
试试下面的代码:
<TextBox x:Name="InvoiceDate" Text="" Width="300" TextAlignment="Left" Height="30" Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" />
<TextBlock IsHitTestVisible="False" Text="Men att läsa" Width="300" TextAlignment="Left" Height="30" Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" Padding="5, 5, 5, 5" Foreground="LightGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=InvoiceDate}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=InvoiceDate, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
您也可以在单击鼠标时执行此操作,假设您的占位符文本是“User_Name”
private void textBox1_MouseClick(object sender, MouseEventArgs e)
{
if(textBox1.Text == "User_Name")
textBox1.Text = "";
}
你也可以这样试试。。
调用函数
TextboxPlaceHolder(this.textBox1, "YourPlaceHolder");
写这个函数
private void TextboxPlaceHolder(Control control, string PlaceHolderText)
{
control.Text = PlaceHolderText;
control.GotFocus += delegate (object sender, EventArgs args)
{
if (cusmode == false)
{
control.Text = control.Text == PlaceHolderText ? string.Empty : control.Text;
//IF Focus TextBox forecolor Black
control.ForeColor = Color.Black;
}
};
control.LostFocus += delegate (object sender, EventArgs args)
{
if (string.IsNullOrWhiteSpace(control.Text) == true)
{
control.Text = PlaceHolderText;
//If not focus TextBox forecolor to gray
control.ForeColor = Color.Gray;
}
};
}
public void Initialize()
{
SetPlaceHolder(loginTextBox, " Логин ");
SetPlaceHolder(passwordTextBox, " Пароль ");
}
public void SetPlaceHolder(Control control, string PlaceHolderText)
{
control.Text = PlaceHolderText;
control.GotFocus += delegate(object sender, EventArgs args) {
if (control.Text == PlaceHolderText)
{
control.Text = "";
}
};
control.LostFocus += delegate(object sender, EventArgs args){
if (control.Text.Length == 0)
{
control.Text = PlaceHolderText;
}
};
}
有更好的解决方案,但最简单的解决方案在这里:将文本框文本设置为所需的字符串,然后创建一个删除文本的函数,让该函数在文本框焦点输入事件上触发
我写了一个可重用的自定义控件,也许它可以帮助需要在他的项目中实现多个占位符文本框的人。
这是带有实例实现示例的自定义类,您可以通过将此代码粘贴到使用 VS 的新 winforms 项目中轻松测试:
namespace reusebleplaceholdertextbox
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// implementation
CustomPlaceHolderTextbox myCustomTxt = new CustomPlaceHolderTextbox(
"Please Write Text Here...", Color.Gray, new Font("ARIAL", 11, FontStyle.Italic)
, Color.Black, new Font("ARIAL", 11, FontStyle.Regular)
);
myCustomTxt.Multiline = true;
myCustomTxt.Size = new Size(200, 50);
myCustomTxt.Location = new Point(10, 10);
this.Controls.Add(myCustomTxt);
}
}
class CustomPlaceHolderTextbox : System.Windows.Forms.TextBox
{
public string PlaceholderText { get; private set; }
public Color PlaceholderForeColor { get; private set; }
public Font PlaceholderFont { get; private set; }
public Color TextForeColor { get; private set; }
public Font TextFont { get; private set; }
public CustomPlaceHolderTextbox(string placeholdertext, Color placeholderforecolor,
Font placeholderfont, Color textforecolor, Font textfont)
{
this.PlaceholderText = placeholdertext;
this.PlaceholderFont = placeholderfont;
this.PlaceholderForeColor = placeholderforecolor;
this.PlaceholderFont = placeholderfont;
this.TextForeColor = textforecolor;
this.TextFont = textfont;
if (!string.IsNullOrEmpty(this.PlaceholderText))
{
SetPlaceHolder(true);
this.Update();
}
}
private void SetPlaceHolder(bool addEvents)
{
if (addEvents)
{
this.LostFocus += txt_lostfocus;
this.Click += txt_click;
}
this.Text = PlaceholderText;
this.ForeColor = PlaceholderForeColor;
this.Font = PlaceholderFont;
}
private void txt_click(object sender, EventArgs e)
{
// IsNotFirstClickOnThis:
// if there is no other control in the form
// we will have a problem after the first load
// because we dont other focusable control to move the focus to
// and we dont want to remove the place holder
// only on first time the place holder will be removed by click event
RemovePlaceHolder();
this.GotFocus += txt_focus;
// no need for this event listener now
this.Click -= txt_click;
}
private void RemovePlaceHolder()
{
this.Text = "";
this.ForeColor = TextForeColor;
this.Font = TextFont;
}
private void txt_lostfocus(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(this.Text))
{
// set placeholder again
SetPlaceHolder(false);
}
}
private void txt_focus(object sender, EventArgs e)
{
if (this.Text == PlaceholderText)
{
// IsNotFirstClickOnThis:
// if there is no other control in the form
// we will have a problem after the first load
// because we dont other focusable control to move the focus to
// and we dont want to remove the place holder
RemovePlaceHolder();
}
}
}
}
让我们用 PlcaeHoldText 和 PlaceHoldBackround 扩展 TextBox。我从我的项目中删除了一些代码。
告别网格或画布!
<TextBox x:Class="VcpkgGui.View.PlaceHoldedTextBox"
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:VcpkgGui.View"
mc:Ignorable="d"
Name="placeHoldTextBox"
TextAlignment="Left"
>
<TextBox.Resources>
<local:FrameworkWidthConverter x:Key="getElemWidth"/>
<local:FrameworkHeightConverter x:Key="getElemHeight"/>
<VisualBrush x:Key="PlaceHoldTextBrush" TileMode="None" Stretch="None" AlignmentX="Left" AlignmentY="Center" Opacity="1">
<VisualBrush.Visual>
<Border Background="{Binding ElementName=placeHoldTextBox, Path=PlaceHoldBackground}"
BorderThickness="0"
Margin="0,0,0,0"
Width="{Binding Mode=OneWay, ElementName=placeHoldTextBox, Converter={StaticResource getElemWidth}}"
Height="{Binding Mode=OneWay, ElementName=placeHoldTextBox, Converter={StaticResource getElemHeight}}"
>
<Label Content="{Binding ElementName=placeHoldTextBox, Path=PlaceHoldText}"
Background="Transparent"
Foreground="#88000000"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
ClipToBounds="True"
Padding="0,0,0,0"
FontSize="14"
FontStyle="Normal"
Opacity="1"/>
</Border>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource PlaceHoldTextBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource PlaceHoldTextBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
using System;
using System.Collections.Generic;
using System.Globalization;
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 VcpkgGui.View
{
/// <summary>
/// PlaceHoldedTextBox.xaml 的交互逻辑
/// </summary>
public partial class PlaceHoldedTextBox : TextBox
{
public string PlaceHoldText
{
get { return (string)GetValue(PlaceHoldTextProperty); }
set { SetValue(PlaceHoldTextProperty, value); }
}
// Using a DependencyProperty as the backing store for PlaceHolderText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlaceHoldTextProperty =
DependencyProperty.Register("PlaceHoldText", typeof(string), typeof(PlaceHoldedTextBox), new PropertyMetadata(string.Empty));
public Brush PlaceHoldBackground
{
get { return (Brush)GetValue(PlaceHoldBackgroundProperty); }
set { SetValue(PlaceHoldBackgroundProperty, value); }
}
public static readonly DependencyProperty PlaceHoldBackgroundProperty =
DependencyProperty.Register(nameof(PlaceHoldBackground), typeof(Brush), typeof(PlaceHoldedTextBox), new PropertyMetadata(Brushes.White));
public PlaceHoldedTextBox() :base()
{
InitializeComponent();
}
}
[ValueConversion(typeof(FrameworkElement), typeof(double))]
internal class FrameworkWidthConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is FrameworkElement elem)
return double.IsNaN(elem.Width) ? elem.ActualWidth : elem.Width;
else
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
[ValueConversion(typeof(FrameworkElement), typeof(double))]
internal class FrameworkHeightConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is FrameworkElement elem)
return double.IsNaN(elem.Height) ? elem.ActualHeight : elem.Height;
else
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
}
我没有使用 TextBox 的 .Text 属性,而是用占位符覆盖了一个 TextBlock。我无法使用 .Text 属性,因为它已绑定到事件。
XAML:
<Canvas Name="placeHolderCanvas">
<TextBox AcceptsReturn="True" Name="txtAddress" Height="50" Width="{Binding ActualWidth, ElementName=placeHolderCanvas}"
Tag="Please enter your address"/>
</Canvas>
VB.NET
Public Shared Sub InitPlaceholder(canvas As Canvas)
Dim txt As TextBox = canvas.Children.OfType(Of TextBox).First()
Dim placeHolderLabel = New TextBlock() With {.Text = txt.Tag,
.Foreground = New SolidColorBrush(Color.FromRgb(&H77, &H77, &H77)),
.IsHitTestVisible = False}
Canvas.SetLeft(placeHolderLabel, 3)
Canvas.SetTop(placeHolderLabel, 1)
canvas.Children.Add(placeHolderLabel)
AddHandler txt.TextChanged, Sub() placeHolderLabel.Visibility = If(txt.Text = "", Visibility.Visible, Visibility.Hidden)
End Sub
txtUsuario.Attributes.Add("placeholder", "Texto");
奇迹般有效。
public class WTextBox : TextBox
{
private string _placeholder;
[Category("Appearance")]
public string Placeholder
{
get { return _placeholder; }
set
{
_placeholder = value ?? string.Empty;
Invalidate();
}
}
public WTextBox()
{
_placeholder = string.Empty;
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg != 0xF || Focused || !string.IsNullOrEmpty(Text) || string.IsNullOrWhiteSpace(_placeholder))
{
return;
}
using (var g = CreateGraphics())
{
TextRenderer.DrawText(g, _placeholder, Font, ClientRectangle, SystemColors.GrayText, BackColor, TextFormatFlags.Left);
}
}
}