我需要在屏幕上设置2组控件:输入和输出(因此它们有2种状态:开启或关)。因此CheckBox
似乎是一个不错的选择。选中输出将设置它。
但是,当显示输入时,将不会与用户进行任何交互。用户只能看到它的值,而不是更改它。
可以考虑可能的解决方案:
CheckBox
。不好:没有工具提示(有可能解决它吗?假面板在顶部?)和视力禁用CheckBox
不好(我不想让用户认为它是禁用)。Label
没有用于On / Off值的好占位符。 RadioButton
看起来有所不同,但它们通常意味着有很多选择,而输入的值是独立的。CheckBox
有点矫枉过正(老实说,我不知道怎么做才能让Win7出现)。是否可以轻松地仅在箱子部件中添加ReadOnly
外观?你们有什么想法?
答案 0 :(得分:8)
有一个解决方案是现有答案的组合。
checkBox.ForeColor = Color.Gray; // Read-only appearance
checkBox.AutoCheck = false; // Read-only behavior
// Tooltip is possible because the checkbox is Enabled
var toolTip = new ToolTip();
toolTip.SetToolTip(checkBox, "This checkbox is read-only.");
结果是CheckBox
Checked
值更改Tooltip
答案 1 :(得分:3)
你必须自己画一切。我认为你应该使用一些具有正确布局的控件来模仿它。以下是您的演示代码,请注意 正确支持AutoSize
。因为绘制的东西总是比默认的东西(AutoSize
使用的)更宽,所以实现AutoSize
并不容易,如果你不太关心AutoSize
,这个对你来说将是最好的控制:
public class XCheckBox : CheckBox
{
public XCheckBox()
{
SetStyle(ControlStyles.Opaque, false);
ReadOnlyCheckedColor = Color.Green;
ReadOnlyUncheckedColor = Color.Gray;
}
public bool ReadOnly { get; set; }
public bool AlwaysShowCheck { get; set; }
public Color ReadOnlyCheckedColor { get; set; }
public Color ReadOnlyUncheckedColor { get; set; }
protected override void OnPaint(PaintEventArgs pevent)
{
if (ReadOnly)
{
pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;
pevent.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
if (AlwaysShowCheck || Checked)
{
RenderCheck(pevent.Graphics);
}
RenderText(pevent.Graphics);
}
else base.OnPaint(pevent);
}
private void RenderCheck(Graphics g)
{
float fontScale = Font.Size / 8.25f;
Size glyphSize = CheckBoxRenderer.GetGlyphSize(g, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
glyphSize.Width = (int) (glyphSize.Width * fontScale);
glyphSize.Height = (int)(glyphSize.Height * fontScale);
string checkAlign = CheckAlign.ToString();
using (GraphicsPath gp = new GraphicsPath())
using (Pen pen = new Pen(Checked ? ReadOnlyCheckedColor : ReadOnlyUncheckedColor, 1.5f)
{
LineJoin = LineJoin.Round,
EndCap = LineCap.Round,
StartCap = LineCap.Round
})
{
gp.AddLine(new Point(3, 7), new Point(5, 10));
gp.AddLine(new Point(5, 10), new Point(8, 3));
float dx = checkAlign.EndsWith("Right") ? Math.Max(-4*fontScale, ClientSize.Width - glyphSize.Width - 4 * fontScale) :
checkAlign.EndsWith("Center") ? Math.Max(-4*fontScale, (ClientSize.Width - glyphSize.Width) / 2 - 4 * fontScale) : -4;
float dy = checkAlign.StartsWith("Bottom") ? Math.Max(-4*fontScale, ClientSize.Height - glyphSize.Height - 4*fontScale) :
checkAlign.StartsWith("Middle") ? Math.Max(-4*fontScale, (ClientSize.Height - glyphSize.Height) / 2 - 4*fontScale) : 0;
g.TranslateTransform(dx, dy);
g.ScaleTransform(1.5f*fontScale, 1.5f*fontScale);
g.DrawPath(pen, gp);
g.ResetTransform();
}
}
private void RenderText(Graphics g)
{
Size glyphSize = CheckBoxRenderer.GetGlyphSize(g, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
float fontScale = Font.Size / 8.25f;
glyphSize.Width = (int)(glyphSize.Width * fontScale);
glyphSize.Height = (int)(glyphSize.Height * fontScale);
string checkAlign = CheckAlign.ToString();
using (StringFormat sf = new StringFormat())
{
string alignment = TextAlign.ToString();
sf.LineAlignment = alignment.StartsWith("Top") ? StringAlignment.Near :
alignment.StartsWith("Middle") ? StringAlignment.Center : StringAlignment.Far;
sf.Alignment = alignment.EndsWith("Left") ? StringAlignment.Near :
alignment.EndsWith("Center") ? StringAlignment.Center : StringAlignment.Far;
sf.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
Rectangle textRectangle = ClientRectangle;
if (checkAlign.EndsWith("Left"))
{
textRectangle.Width -= glyphSize.Width;
textRectangle.Offset(glyphSize.Width, 0);
}
else if (checkAlign.EndsWith("Right"))
{
textRectangle.Width -= glyphSize.Width;
textRectangle.X = 0;
}
g.DrawString(Text, Font, new SolidBrush(ForeColor), textRectangle, sf);
}
}
bool suppressCheckedChanged;
protected override void OnClick(EventArgs e)
{
if (ReadOnly) {
suppressCheckedChanged = true;
Checked = !Checked;
suppressCheckedChanged = false;
}
base.OnClick(e);
}
protected override void OnCheckedChanged(EventArgs e)
{
if (suppressCheckedChanged) return;
base.OnCheckedChanged(e);
}
}
注意:代码未完全实现,所有内容都尽可能简单。您可以更改AlwaysShowCheck
属性以选择ReadOnly
未选中状态,它可以是灰色刻度或无。您可以将ReadOnly
设置为true
,使其成为只读视觉。
AlwaysShowCheck
设置为true
(ReadOnly未选中状态以灰色刻度标记表示)
AlwaysShowCheck
设置为false
(ReadOnly未选中状态由任何内容表示)
答案 2 :(得分:3)
这是旧文章,但仍然有用,所以这是我的解决方法。
为了进行只读操作:
CheckBox
上时禁用突出显示我们可以继承CheckBox
类并禁用鼠标和键盘交互:
public class ReadOnlyCheckBox : CheckBox
{
[System.ComponentModel.Category("Behavior")]
[System.ComponentModel.DefaultValue(false)]
public bool ReadOnly { get; set; } = false;
protected override void OnMouseEnter(EventArgs e)
{
// Disable highlight when the cursor is over the CheckBox
if (!ReadOnly) base.OnMouseEnter(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// Disable reacting (logically or visibly) to a mouse click
if (!ReadOnly) base.OnMouseDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
// Suppress space key to disable checking/unchecking
if (!ReadOnly || e.KeyData != Keys.Space) base.OnKeyDown(e);
}
}
为了使CheckBox
是只读的,我们可以根据ForColor
属性更改ReadOnly
。
注意:更改ForColor
仅会更改文本颜色,选中标记的颜色只能通过覆盖OnPaint
方法并重绘CheckBox
来更改(据我所知)。
以下是先前代码的扩展版本,该代码根据ForColor
属性更改了ReadOnly
:
public class ReadOnlyCheckBox : CheckBox
{
private bool _readOnly = false;
private Color _readOnlyForeColor = Color.Gray;
private Color _normalForeColor = Color.Black;
[System.ComponentModel.Category("Behavior")]
[System.ComponentModel.DefaultValue(false)]
public bool ReadOnly
{
get => _readOnly;
set
{
if (_readOnly != value)
{
_readOnly = value;
UpdateForColor();
}
}
}
[System.ComponentModel.Category("Appearance")]
[System.ComponentModel.DefaultValue(typeof(Color), "Black")]
public Color NormalForeColor
{
get => _normalForeColor;
set
{
if (_normalForeColor != value)
{
_normalForeColor = value;
UpdateForColor();
}
}
}
[System.ComponentModel.Category("Appearance")]
[System.ComponentModel.DefaultValue(typeof(Color), "Gray")]
public Color ReadOnlyForeColor
{
get => _readOnlyForeColor;
set
{
if (_readOnlyForeColor != value)
{
_readOnlyForeColor = value;
UpdateForColor();
}
}
}
// Hide ForeColor from the editor
[System.ComponentModel.Browsable(false)]
[System.ComponentModel.EditorBrowsable(
System.ComponentModel.EditorBrowsableState.Never)]
public override Color ForeColor
{
get => base.ForeColor;
set => base.ForeColor = value;
}
public ReadOnlyCheckBox()
{
UpdateForColor();
}
private void UpdateForColor()
{
ForeColor = ReadOnly ? ReadOnlyForeColor : NormalForeColor;
}
protected override void OnMouseEnter(EventArgs e)
{
// Disable highlight when the cursor is over the CheckBox
if (!ReadOnly) base.OnMouseEnter(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// Disable reacting (logically or visibly) to a mouse click
if (!ReadOnly) base.OnMouseDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
// Suppress space key to disable checking/unchecking
if (!ReadOnly || e.KeyData != Keys.Space) base.OnKeyDown(e);
}
}
答案 3 :(得分:0)
您可以为侦听器提供单击 CheckBox 的事件,因为可以在运行时取消其常用流程。
答案 4 :(得分:0)
到目前为止,最简单的解决方案(积分转到ShadowWizard)是设置ForeColor = Color.Gray
,这会让用户思考,CheckBox
被禁用了。
与Enabled = false
相比,优点是:
ToolTip
正在运作; 没有弊端。
答案 5 :(得分:0)
Visual Studio现已提供: 属性 - >属性 - > ReadOnly:)
答案 6 :(得分:0)
没有必要编写整个控件,只需编写' Checkbox'的衍生物。 A' ReadOnly'属性被添加到控件中,这会导致控件在何时可以更改其值
时进行处理public class CheckBoxReadOnly : CheckBox
{
private bool _ReadOnly = false;
[DefaultValue(false)]
public bool ReadOnly {
get { return _ReadOnly; }
set {
if (_ReadOnly != value) {
EventArgs e = new EventArgs();
_ReadOnly = value;
OnReadOnlyChanged(e);
}
}
}
protected void OnReadOnlyChanged(EventArgs e)
{
if (ReadOnlyChanged != null) {
ReadOnlyChanged(this, e);
}
}
public event ReadOnlyChanged;
protected override void OnCheckedChanged(EventArgs e)
{
static Int16 flag;
if (ReadOnly) {
flag += 1;
if (flag == 1)
Checked = !Checked;
} else {
base.OnCheckedChanged(e);
}
flag = 0;
}
}
答案 7 :(得分:-1)
在属性表中,只需将选择模式设为无。