文本框的覆盖文本 属性 未正确刷新
Overrided Text property of a Textbox does not refresh properly
我正在创建自定义控件(带水印的文本框),它继承自文本框。截至目前,文本框在没有文本时正确显示失去焦点时的水印,并在文本框获得焦点时将其删除(如果是水印,它甚至会更改文本的颜色)。 我想让它做的是在显示水印时报告它没有文本,所以我试图覆盖文本 属性。
代码如下:
public class WatermarkedTextbox : TextBox
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
_isWatermarked = true;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
ForeColor = SystemColors.ControlText;
Text = string.Empty;
_isWatermarked = false;
}
}
}
问题是,当文本框获得焦点时,它不会删除水印。
我哪里错了missing/doing?
删除您覆盖的文本 属性,然后它将起作用!
删除这些行:
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
啊抱歉我没看清楚。或者,您可能不想通过覆盖文本 属性.
来通知
您可以这样使用事件:
public class WatermarkedTextbox : TextBox, INotifyPropertyChanged
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
public bool IsWaterMarked
{
get
{
return _isWatermarked;
}
set
{
_isWatermarked = value;
OnPropertyChanged("IsWaterMarked");
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
IsWaterMarked = true;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
ForeColor = SystemColors.ControlText;
Text = string.Empty;
IsWaterMarked = false;
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
然后在主窗体上,您可以订阅并向 属性Changed 事件添加处理程序:
//somewhere, like in the forms constructor, you need to subscribe to this event
watermarkedTextbox2.PropertyChanged += watermarkedTextbox2_PropertyChanged;
// the handler function
void watermarkedTextbox2_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsWaterMarked")
{
if (watermarkedTextbox2.IsWaterMarked)
; //handle here
else
; //handle here
}
}
Windows 支持文本框(和组合框等其他编辑控件)的水印,他们称之为 "cue banner"。但是请注意,这不适用于多行文本框。
在受支持的控件上设置提示横幅只需使用 Win32 API 向包含水印文本的控件发送 EM_SETCUEBANNER
消息即可。 Windows 然后将检测控件何时为空或具有焦点并为您完成所有艰苦的工作,您无需使用事件来管理状态。当您获得控件的 Text
属性.
时,提示横幅也会被忽略
我使用以下助手 class 设置提示横幅(也适用于组合框):
public class CueBannerHelper
{
#region Win32 API's
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO
{
public int cbSize;
public RECT rcItem;
public RECT rcButton;
public IntPtr stateButton;
public IntPtr hwndCombo;
public IntPtr hwndItem;
public IntPtr hwndList;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
/// <summary>Used to get the current Cue Banner on an edit control.</summary>
public const int EM_GETCUEBANNER = 0x1502;
/// <summary>Used to set a Cue Banner on an edit control.</summary>
public const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hwnd, ref COMBOBOXINFO pcbi);
[DllImport("user32.dll")]
public static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
#endregion
#region Method members
public static void SetCueBanner(Control control, string cueBanner) {
if (control is ComboBox) {
CueBannerHelper.COMBOBOXINFO info = new CueBannerHelper.COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
CueBannerHelper.GetComboBoxInfo(control.Handle, ref info);
CueBannerHelper.SendMessage(info.hwndItem, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner);
}
else {
CueBannerHelper.SendMessage(control.Handle, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner);
}
}
#endregion
}
在自定义 TextBox 控件上实现水印所需的全部内容如下 属性(顶部的属性用于控件的设计时属性):
/// <summary>
/// Gets or sets the watermark that the control contains.
/// </summary>
[Description("The watermark that the control contains."),
Category("Appearance"),
DefaultValue(null),
Browsable(true)
]
public string Watermark {
get { return this._watermark; }
set {
this._watermark = value;
CueBannerHelper.SetCueBanner(this, value);
}
}
Hans Passant 的评论是我问题的正确答案。另外,感谢所有花时间提供帮助的人。
我最终决定走最简单的路线(处理 PropertyChanged
对于这个特殊需求来说似乎太复杂了,挂钩 Windows API 省去了多行文本框,所以这不是一个选择)。
如果有人需要,这里是代码:
public class WatermarkedTextbox : TextBox
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
_isWatermarked = true;
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
_isWatermarked = false;
ForeColor = SystemColors.ControlText;
Text = string.Empty;
}
}
}
我正在创建自定义控件(带水印的文本框),它继承自文本框。截至目前,文本框在没有文本时正确显示失去焦点时的水印,并在文本框获得焦点时将其删除(如果是水印,它甚至会更改文本的颜色)。 我想让它做的是在显示水印时报告它没有文本,所以我试图覆盖文本 属性。
代码如下:
public class WatermarkedTextbox : TextBox
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
_isWatermarked = true;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
ForeColor = SystemColors.ControlText;
Text = string.Empty;
_isWatermarked = false;
}
}
}
问题是,当文本框获得焦点时,它不会删除水印。
我哪里错了missing/doing?
删除您覆盖的文本 属性,然后它将起作用!
删除这些行:
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
啊抱歉我没看清楚。或者,您可能不想通过覆盖文本 属性.
来通知您可以这样使用事件:
public class WatermarkedTextbox : TextBox, INotifyPropertyChanged
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
public bool IsWaterMarked
{
get
{
return _isWatermarked;
}
set
{
_isWatermarked = value;
OnPropertyChanged("IsWaterMarked");
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
IsWaterMarked = true;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
ForeColor = SystemColors.ControlText;
Text = string.Empty;
IsWaterMarked = false;
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
然后在主窗体上,您可以订阅并向 属性Changed 事件添加处理程序:
//somewhere, like in the forms constructor, you need to subscribe to this event
watermarkedTextbox2.PropertyChanged += watermarkedTextbox2_PropertyChanged;
// the handler function
void watermarkedTextbox2_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsWaterMarked")
{
if (watermarkedTextbox2.IsWaterMarked)
; //handle here
else
; //handle here
}
}
Windows 支持文本框(和组合框等其他编辑控件)的水印,他们称之为 "cue banner"。但是请注意,这不适用于多行文本框。
在受支持的控件上设置提示横幅只需使用 Win32 API 向包含水印文本的控件发送 EM_SETCUEBANNER
消息即可。 Windows 然后将检测控件何时为空或具有焦点并为您完成所有艰苦的工作,您无需使用事件来管理状态。当您获得控件的 Text
属性.
我使用以下助手 class 设置提示横幅(也适用于组合框):
public class CueBannerHelper
{
#region Win32 API's
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO
{
public int cbSize;
public RECT rcItem;
public RECT rcButton;
public IntPtr stateButton;
public IntPtr hwndCombo;
public IntPtr hwndItem;
public IntPtr hwndList;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
/// <summary>Used to get the current Cue Banner on an edit control.</summary>
public const int EM_GETCUEBANNER = 0x1502;
/// <summary>Used to set a Cue Banner on an edit control.</summary>
public const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hwnd, ref COMBOBOXINFO pcbi);
[DllImport("user32.dll")]
public static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
#endregion
#region Method members
public static void SetCueBanner(Control control, string cueBanner) {
if (control is ComboBox) {
CueBannerHelper.COMBOBOXINFO info = new CueBannerHelper.COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
CueBannerHelper.GetComboBoxInfo(control.Handle, ref info);
CueBannerHelper.SendMessage(info.hwndItem, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner);
}
else {
CueBannerHelper.SendMessage(control.Handle, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner);
}
}
#endregion
}
在自定义 TextBox 控件上实现水印所需的全部内容如下 属性(顶部的属性用于控件的设计时属性):
/// <summary>
/// Gets or sets the watermark that the control contains.
/// </summary>
[Description("The watermark that the control contains."),
Category("Appearance"),
DefaultValue(null),
Browsable(true)
]
public string Watermark {
get { return this._watermark; }
set {
this._watermark = value;
CueBannerHelper.SetCueBanner(this, value);
}
}
Hans Passant 的评论是我问题的正确答案。另外,感谢所有花时间提供帮助的人。
我最终决定走最简单的路线(处理 PropertyChanged
对于这个特殊需求来说似乎太复杂了,挂钩 Windows API 省去了多行文本框,所以这不是一个选择)。
如果有人需要,这里是代码:
public class WatermarkedTextbox : TextBox
{
private bool _isWatermarked;
private string _watermark;
public string Watermark
{
get { return _watermark; }
set { _watermark = value; }
}
[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return _isWatermarked ? string.Empty : base.Text;
}
set
{
base.Text = value;
}
}
public WatermarkedTextbox()
{
GotFocus += WatermarkedTextbox_GotFocus;
LostFocus += WatermarkedTextbox_LostFocus;
}
private void WatermarkedTextbox_LostFocus(object sender, EventArgs e)
{
if (Text.Length == 0)
{
_isWatermarked = true;
ForeColor = SystemColors.InactiveCaption;
Text = _watermark;
}
}
private void WatermarkedTextbox_GotFocus(object sender, EventArgs e)
{
if (_isWatermarked)
{
_isWatermarked = false;
ForeColor = SystemColors.ControlText;
Text = string.Empty;
}
}
}