[英]Read-only (visually) CheckBox
I need to have 2 groups of controls on the screen: inputs and outputs (so they have 2 states: On or Off ).我需要在屏幕上有 2 组控件:输入和输出(因此它们有 2 个状态: On或Off )。 Thus CheckBox
seems to be a good choice.因此CheckBox
似乎是一个不错的选择。 Checking any output will set it.检查任何输出都会设置它。
However, when displaying inputs there will be no user interaction with it.但是,当显示输入时,不会有用户与之交互。 User is only allowed to see its value, not to change it.用户只能看到它的值,不能改变它。
Could think about possible solutions:可以考虑一下可能的解决方案:
CheckBox
disabled.禁用CheckBox
。 Bad: there will be no tooltip (possible to solve it? by fake panel on top?) and visually disabled CheckBox
is not nice (and I don't want to make user think it is disabled ).不好:将没有工具提示(可能解决它?通过顶部的假面板?)并且视觉上禁用的CheckBox
不好(我不想让用户认为它已禁用)。Label
doesn't have nice placeholder for the On/Off value. Label
没有很好的开/关值占位符。 RadioButton
look differently, but they usually means there is a single choice out of many, while values of inputs are independent. RadioButton
看起来不同,但它们通常意味着只有一个选择,而输入的值是独立的。CheckBox
is a bit overkill (and honestly, I don't know how to do it to have Win7 appearance).绘制整个CheckBox
有点矫枉过正(老实说,我不知道如何做到这一点才能拥有 Win7 外观)。 Would it be possible to add only ReadOnly
appearance to the box part easily?是否可以轻松地将ReadOnly
外观添加到盒子部分?What do you guys think?你们有什么感想?
There is a solution that is combination of the existing answers.有一个解决方案是现有答案的组合。
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.");
The result is a CheckBox
that结果是一个CheckBox
Checked
value from changing when clicked防止Checked
值在单击时发生变化Tooltip
支持Tooltip
This is an old post but still can be usefull so here is my solution.这是一篇旧帖子,但仍然有用,所以这是我的解决方案。
In order to make a read-only behavior:为了使只读行为:
CheckBox
当光标在CheckBox
时禁用突出显示We can inherit the CheckBox
class and disable mouse and keyboard interaction:我们可以继承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);
}
}
In order to make it visually apparent that the CheckBox
is read-only, we can change the ForColor
according to the ReadOnly
property.为了使CheckBox
是只读的,在视觉上显而易见,我们可以根据ReadOnly
属性更改ForColor
。
Note: changing the ForColor
only changes the text color, the colors of the checkmark can only be changed by overriding the OnPaint
method and repainting the CheckBox
(as far as I know).注意:更改ForColor
只会更改文本颜色,复选标记的颜色只能通过覆盖OnPaint
方法并重新绘制CheckBox
来更改(据我所知)。
Here is an extended version of the previous code that changes the ForColor
according to the ReadOnly
property:这是先前代码的扩展版本, ForColor
根据ReadOnly
属性更改ForColor
:
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);
}
}
You have to draw everything yourself.你必须自己画一切。 I think you should use some controls with correct layout to mimic it.我认为您应该使用一些具有正确布局的控件来模仿它。 Here is the demo code for you, note that it does not support AutoSize
correctly.这是您的演示代码,请注意它不正确支持AutoSize
。 Because the drawn stuff is always wider than the default stuff (which the AutoSize
works with), implementing the AutoSize
is not easy, If you don't care too much about AutoSize
, this would be the great control for you:因为绘制的东西总是比默认的东西( 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);
}
}
NOTE : The code is not fully implemented, everything is kept as simple as possible.注意:代码没有完全实现,一切都尽可能简单。 You can change the AlwaysShowCheck
property to choose the ReadOnly
unchecked state, it can be a gray tick mark or nothing .您可以更改AlwaysShowCheck
属性以选择ReadOnly
未选中状态,它可以是灰色刻度线或没有。 You can set the ReadOnly
to true
to make it Read-only visual .您可以将ReadOnly
设置为true
以使其成为Read-only visual 。
AlwaysShowCheck
is set to true
(the ReadOnly unchecked state is indicated by a gray tick mark) AlwaysShowCheck
设置为true
(ReadOnly 未选中状态由灰色勾号指示)
AlwaysShowCheck
is set to false
(the ReadOnly unchecked state is indicated by nothing) AlwaysShowCheck
设置为false
(ReadOnly 未选中状态由AlwaysShowCheck
指示)
您可以为单击CheckBox
的事件提供侦听器,因为可以在运行时取消其通常的流程。
So far the easiest solution (credits go to ShadowWizard) is to set ForeColor = Color.Gray
, this makes user think, what CheckBox
is disabled.到目前为止,最简单的解决方案(学分转到 ShadowWizard)是设置ForeColor = Color.Gray
,这让用户思考,什么CheckBox
被禁用。
Compared to Enabled = false
, pluses are:与Enabled = false
相比,优点是:
ToolTip
is working; ToolTip
正在工作;No minuses.没有缺点。
It is not necessary to write the entire control, just write a derivative of Checkbox
.没必要写整个控件,只写一个Checkbox
的派生类即可。
A ReadOnly
property is added to the control, this causes the control to handle when it can change its value. ReadOnly
属性被添加到控件,这会导致控件在它可以更改其值时进行处理。
public class CheckBoxReadOnly : CheckBox
{
private bool _readOnly = false;
[DefaultValue(false)]
public bool ReadOnly
{
get { return _readOnly; }
set
{
if (_readOnly != value)
{
_readOnly = value;
OnReadOnlyChanged(new EventArgs());
}
}
}
int _flag = 0;
public event EventHandler ReadOnlyChanged;
protected void OnReadOnlyChanged(EventArgs e)
{
ReadOnlyChanged?.Invoke(this, e);
}
protected override void OnCheckedChanged(EventArgs e)
{
if (ReadOnly)
{
_flag++;
if (_flag == 1)
Checked = !Checked;
}
else
{
base.OnCheckedChanged(e);
}
_flag = 0;
}
}
在属性表中,只需将选择模式设为无。
Visual Studio 现在可以在以下位置使用它:属性 -> 属性 -> 只读 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.