【发布时间】:2017-03-17 11:26:43
【问题描述】:
我创建了一个包含多个用户控件的项目,以支持 winform 的透明度、渐变和主题。
我正在寻找一种方法来创建textbox 的替代品,因为winforms 文本框没有使用其他winforms 控件使用的常规OnPaint 和OnPaintBackground,果然,我找到了可以使用@ 的东西987654321@ Brian 的评论给了我解决方案 - 在我自己的控件中包装一个透明的 RichTextBox。
但是,这带来了一个我不知道如何解决的新问题 - TabIndex 属性没有按预期运行。
对于普通文本框,当您有多个文本框并且每个文本框都有不同的选项卡索引时,焦点会按照选项卡索引指定的顺序从一个文本框移到另一个文本框。在我的情况下,它没有。相反,它是不可预测的。 我已经尝试了多种具有不同布局和控件的表单,但我似乎找不到任何可预测的行为模式来暗示问题。
这是相关控件的代码(如果重要,父级 ZControl 会继承 UserControl):
/// <summary>
/// A stylable textbox.
/// <Remarks>
/// The solution for writing a stylable textbox was inspired by this SO post and Brian's comment:
/// https://stackoverflow.com/a/4360341/3094533
/// </Remarks>
/// </summary>
[DefaultEvent("TextChanged")]
public partial class ZTextBox : ZControl
{
#region ctor
public ZTextBox()
{
TextBox = new TransparentRichTextBox();
TextBox.BackColor = Color.Transparent;
TextBox.BorderStyle = BorderStyle.None;
TextBox.Multiline = false;
TextBox.TextChanged += TextBox_TextChanged;
TextBox.TabStop = true;
TextBox.AcceptsTab = false;
InitializeComponent();
AdjustTextBoxRectangle();
this.Controls.Add(TextBox);
this.RoundedCorners.PropertyChanged += RoundedCorners_PropertyChanged;
}
#endregion ctor
#region properties
private TransparentRichTextBox TextBox { get; }
public override string Text
{
get
{
return TextBox.Text;
}
set
{
TextBox.Text = value;
}
}
[DefaultValue(false)]
public bool Multiline
{
get
{
return this.TextBox.Multiline;
}
set
{
this.TextBox.Multiline = value;
}
}
public override Font Font
{
get
{
return base.Font;
}
set
{
if (base.Font != value)
{
base.Font = value;
if (TextBox != null)
{
TextBox.Font = value;
}
}
}
}
public new int TabIndex
{
get
{
return this.TextBox.TabIndex;
}
set
{
this.TextBox.TabIndex = value;
}
}
#region hidden properties
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public override Color ForeColor
{
get
{
return TextBox.ForeColor;
}
set
{
TextBox.ForeColor = value;
}
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public override ContentAlignment TextAlign
{
get
{
return base.TextAlign;
}
set
{
base.TextAlign = value;
}
}
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public override Point TextLocationOffset
{
get
{
return base.TextLocationOffset;
}
set
{
base.TextLocationOffset = value;
}
}
#endregion hidden properties
#endregion properties
#region methods
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
TextBox.Focus();
}
protected override void DrawText(Graphics graphics, string text, ContentAlignment textAlign, Point locationOffset, Size stringSize)
{
// Do nothing - The transparent rich textbox is responsible for drawing the text...
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
AdjustTextBoxRectangle();
}
private void AdjustTextBoxRectangle()
{
var corners = this.RoundedCorners.Corners;
var leftAdjustment = ((corners & RoundedEdges.TopLeft) == RoundedEdges.TopLeft || (corners & RoundedEdges.BottomLeft) == RoundedEdges.BottomLeft) ? this.RoundedCorners.ArcSize / 2 : 0;
var rightAdjustment = ((corners & RoundedEdges.TopRight) == RoundedEdges.TopRight || (corners & RoundedEdges.BottomRight) == RoundedEdges.BottomRight) ? this.RoundedCorners.ArcSize / 2 : 0;
TextBox.Top = 0;
TextBox.Left = leftAdjustment;
TextBox.Width = this.Width - leftAdjustment - rightAdjustment;
TextBox.Height = this.Height;
}
#endregion methods
#region event handlers
private void RoundedCorners_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
AdjustTextBoxRectangle();
}
private void TextBox_TextChanged(object sender, EventArgs e)
{
OnTextChanged(e);
}
#endregion event handlers
#region private classes
private class TransparentRichTextBox : RichTextBox
{
public TransparentRichTextBox()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams
{
get
{
CreateParams parms = base.CreateParams;
parms.ExStyle |= 0x20; // Turn on WS_EX_TRANSPARENT
return parms;
}
}
}
#endregion private classes
}
还有设计器代码,如果相关的话:
partial class ZTextBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// ZTextBox
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.Name = "ZTextBox";
this.RoundedCorners.ArcSize = 50;
this.RoundedCorners.Corners = Zohar.UserControls.RoundedEdges.None;
this.Size = new System.Drawing.Size(100, 20);
this.Style.DisabledStyle.BackColor = System.Drawing.Color.Empty;
this.Style.DisabledStyle.BackgroundImage = null;
this.Style.DisabledStyle.BorderColor = System.Drawing.Color.Empty;
this.Style.DisabledStyle.ForeColor = System.Drawing.Color.Empty;
this.Style.DisabledStyle.Gradient.Angle = 0F;
this.Style.DisabledStyle.Gradient.BackColor = System.Drawing.Color.Empty;
this.Style.DisabledStyle.Image = null;
this.Style.DisabledStyle.Name = null;
this.Style.EnabledStyle.BackColor = System.Drawing.Color.Empty;
this.Style.EnabledStyle.BackgroundImage = null;
this.Style.EnabledStyle.BorderColor = System.Drawing.Color.Empty;
this.Style.EnabledStyle.ForeColor = System.Drawing.Color.Empty;
this.Style.EnabledStyle.Gradient.Angle = 0F;
this.Style.EnabledStyle.Gradient.BackColor = System.Drawing.Color.Empty;
this.Style.EnabledStyle.Image = null;
this.Style.EnabledStyle.Name = null;
this.Style.HoverStyle.BackColor = System.Drawing.Color.Empty;
this.Style.HoverStyle.BackgroundImage = null;
this.Style.HoverStyle.BorderColor = System.Drawing.Color.Empty;
this.Style.HoverStyle.ForeColor = System.Drawing.Color.Empty;
this.Style.HoverStyle.Gradient.Angle = 0F;
this.Style.HoverStyle.Gradient.BackColor = System.Drawing.Color.Empty;
this.Style.HoverStyle.Image = null;
this.Style.HoverStyle.Name = null;
this.ResumeLayout(false);
}
#endregion
}
【问题讨论】:
-
您是否将控件放置在表格布局面板中?
-
不,我已经将它们放在表单中一次,其中没有其他控件 - tabindex 似乎正在向后工作。我已经将它们放在另一个容器中(也继承了 ZControl),该选项卡似乎根本不起作用。我尽量避免使用表格布局面板。
-
不幸的是,如果您想完成这项工作,您将不得不使用表格布局面板。 Caz 一旦我遇到与您相同的问题,我就以这种方式解决了问题。与表格布局面板一样,您也可以实现响应性
-
是TabIndex属性,很微妙。基本问题是设置它的值不会强制设计者重写 InitializeComponent() 方法。如果您更改多个属性,而不是仅更改 TabIndex,则有效。您还需要摆脱 OnGetFocus() 覆盖,这可能是让您修改 TabIndex 的那个。 UserControl 已经这样做了。
-
@hans 谢谢,我会在我的电脑前试一试。
标签: c# winforms user-controls