向文本框添加占位符文本

我正在寻找一种方法来添加占位符文本到文本框,就像你可以与文本框在 html5。

也就是说,如果文本框没有文本,那么它会添加文本 Enter some text here,当用户点击它时,占位符文本会消失,并允许用户输入他们自己的文本,如果文本框失去焦点,仍然没有文本,那么占位符会被添加回文本框。

374400 次浏览

不就是这样吗:

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...";
}

这只是伪代码,但概念是存在的。

您可以通过覆盖 TextBlock来修改 得到默认的 Template,并使用 Style添加隐藏并以正确状态显示它的触发器。

你可以用这个,它对我很有效,而且是个非常简单的解决方案。

    <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"/>

我想出了一个适合我的方法,但只是因为我愿意使用文本框的名称作为我的占位符。请看下面。

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;
}
}

不需要处理焦点进入和焦点离开事件来设置和删除占位符文本,而是可以使用 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");

参考资料: 为文本框设置占位符文本(提示文本)

尝试以下代码:

<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 = "";
}

这意味着你有一个按钮,允许你做一个动作,如登录或东西。在执行操作之前,检查文本框是否已填充。如果没有,它将替换文本

 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 # 得到一个更好的解决方案。

属性。添加(“占位符”,“ Texto”) ;

这不是我的代码,但我使用它很多,它的工作完美... 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 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;
}
};
}

附属财产的救援:

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>

添加此类您的项目并生成解决方案。单击 VisualStudio 上的 Toolbox,您将看到一个名为 PlaceholderTextBox 的新文本框组件。在表单设计中删除当前文本框,并替换为 PlaceHolderTextBox。

enter image description here

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();
}
}

根据 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;
}
}

我没有使用 TextBox 的.Text 属性,而是用占位符覆盖了 TextBlock。 我无法使用.Text 属性,因为它绑定到了 Event。

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

结果: enter image description here

虽然使用 EM_SETCUEBANNER消息可能是最简单的,但是我不喜欢占位符文本在控件获得焦点时消失。这是我填表格时最讨厌的事。我必须点击它才能记住这个字段是用来做什么的。

因此,这里是另一个解决方案的 WinForms。它覆盖了控件顶部的 Label,只有当用户开始键入时 Label才会消失。

肯定不是防弹的。它接受任何 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;
}
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"/>

你也可以这样试试。

调用函数

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;
}


};
}

在这里,我来与这个解决方案的灵感@凯末尔卡拉达格。

我注意到这里发布的每个解决方案都依赖于焦点,

我希望我的占位符是 Google Chrome 中标准 HTML 占位符的完全克隆。

当框被聚焦时,不再隐藏/显示占位符,

我隐藏/显示占位符取决于框的文本长度:

如果该框为空,则显示占位符,如果键入该框,则占位符将消失。

由于它是从标准 TextBox 继承而来的,因此您可以在您的工具箱中找到它!

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();
}
}
}

有更好的解决方案,但最简单的解决方案在这里: 将文本框文本设置为所需的字符串 然后创建一个删除文本的函数,在文本框 Focus Enter 事件上激发该函数

用于 WindowsFormsTextBox 控件的非常有效的解决方案 给你

这也可以在 Multliline 模式下使用。

也许它可以扩展到其他控件,比如 ComboBox 控件(未选中)

我写了一个可重用的自定义控件,也许它可以帮助有人需要实现多个占位符文本框在他的项目。< br/> 这里是一个带有实例实现示例的自定义类,您可以使用 VS 轻松地将此代码粘贴到一个新的 winform 项目上进行测试:

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();
}
}
}
}

非常有效。

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);
}
}
}

这是文本框的扩展方法。只需以编程方式添加占位符文本:

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

让我们用 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;
}
}


}

我知道这是一个老线程,但是.NET Core 和.NET 5.0已经实现了 TextBox.PlaceholderText属性。

Https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.textbox.placeholdertext?view=net-5.0