只读(可视)CheckBox

时间:2013-11-11 09:22:04

标签: c# winforms checkbox

我需要在屏幕上设置2组控件:输入输出(因此它们有2种状态:开启)。因此CheckBox似乎是一个不错的选择。选中输出将设置它。

但是,当显示输入时,将不会与用户进行任何交互。用户只能看到它的值,而不是更改它。

问题:如何使checkbos在视觉上显示为只读

可以考虑可能的解决方案:

  • 禁用CheckBox。不好:没有工具提示(有可能解决它吗?假面板在顶部?)和视力禁用CheckBox不好(我不想让用户认为它是禁用)。
  • 使用不同的控件。哪一个? Label没有用于On / Off值的好占位符。 RadioButton看起来有所不同,但它们通常意味着有很多选择,而输入的值是独立的。
  • 制作自己的组件。绘制整个CheckBox有点矫枉过正(老实说,我不知道怎么做才能让Win7出现)。是否可以轻松地仅在箱子部件中添加ReadOnly外观?

你们有什么想法?

8 个答案:

答案 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未选中状态以灰色刻度标记表示)

enter image description here

AlwaysShowCheck设置为false(ReadOnly未选中状态由任何内容表示)

enter image description here

答案 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)

在属性表中,只需将选择模式设为无。