C# 只读(可视)复选框

C# 只读(可视)复选框,c#,winforms,checkbox,C#,Winforms,Checkbox,我需要在屏幕上有两组控件:输入和输出(因此它们有两种状态:打开或关闭)。因此,复选框似乎是一个不错的选择。检查任何输出将设置它 但是,当显示输入时不会与用户交互。用户只允许查看其值,不允许更改它 问题:如何使复选框以只读形式直观显示? 可以考虑可能的解决方案: 禁用复选框。坏:将没有工具提示(可能解决吗?通过顶部的假面板?),视觉上禁用的复选框不好(我不想让用户认为它被禁用) 使用不同的控件。哪一个标签没有用于开/关值的好的占位符RadioButton看起来不同,但它们通常意味着在许多选项中只

我需要在屏幕上有两组控件:输入输出(因此它们有两种状态:打开或关闭)。因此,
复选框
似乎是一个不错的选择。检查任何输出将设置它

但是,当显示输入时不会与用户交互。用户只允许查看其值,不允许更改它

问题:如何使复选框以只读形式直观显示? 可以考虑可能的解决方案:

  • 禁用
    复选框
    。坏:将没有工具提示(可能解决吗?通过顶部的假面板?),视觉上禁用的
    复选框
    不好(我不想让用户认为它被禁用)
  • 使用不同的控件。哪一个<代码>标签没有用于开/关值的好的占位符
    RadioButton
    看起来不同,但它们通常意味着在许多选项中只有一个选项,而输入的值是独立的
  • 制作自己的组件。绘制整个
    复选框有点过火(老实说,我不知道如何才能使其具有Win7外观)。是否可以轻松地将仅
    只读
    外观添加到长方体零件

你们觉得怎么样?

你们可以为点击
复选框的事件提供一个监听器,因为它可以在运行时取消它通常的流程。

到目前为止,最简单的解决方案(进入阴影向导)是设置
ForeColor=Color.Gray
,这会让用户想到,
复选框
被禁用了

Enabled=false
相比,优点是:

  • 工具提示
    正在工作
  • 长方体部分看起来很漂亮(鼠标悬停时会有反应,无论何时选中或取消选中,都可以非常清晰地看到)

没有缺点。

你必须自己画所有的东西。我认为你应该使用一些布局正确的控件来模拟它。这是您的演示代码,请注意,它不支持正确地自动调整大小。由于绘制的填充始终比默认填充宽(《代码》)自动调整大小(《代码》)可以使用,因此实现<代码>自动调整大小
并不容易,如果您不太在意<代码>自动调整大小
,这将是一个很好的控制:

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
(只读未选中状态由灰色勾号指示)

AlwaysShowCheck
设置为
false
(只读未选中状态由零指示)


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

有一个解决方案,它是现有答案的组合

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.");
结果是一个
复选框

  • 以灰色文本显示已禁用
  • 防止单击时更改选中的
  • 支持
    工具提示

Visual studio现在可在以下位置使用:
属性->属性->只读:)

无需编写整个控件,只需编写
复选框的派生项即可

控件中添加了一个
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;
    }
}

这是一个老帖子,但仍然可以使用,所以这里是我的解决方案

要进行只读行为,请执行以下操作:

  • 当光标位于
    复选框上方时禁用高亮显示
  • 禁用对鼠标单击的反应(逻辑或可见)
  • 启用工具提示
我们可以继承
复选框
类并禁用鼠标和键盘交互:

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);
    }
}
为了使
复选框
是只读的,我们可以根据
只读
属性更改
ForColor

注意:更改
for color
只会更改文本颜色,只能通过覆盖
on paint
方法并重新绘制
复选框来更改复选标记的颜色(据我所知)

以下是先前代码的扩展版本,它根据
只读属性更改了
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);
    }
}

@CodeCaster可能重复,我的问题不同。我知道如何防止用户使用该控件,但它在视觉上仍然与“准备单击”复选框相同。这就是我的问题,向用户显示抱歉,但我是只读复选框。我可以通过设置
AutoCheckbox=false
轻松实现这一点。问题在于视觉外观,而不是事件或动作。@Sinatr您的意思是
AutoCheck
,但这有什么错?视觉外观将完全相同,用户将无法更改复选框状态,使其成为只读复选框。这不是你想要的吗?@ShadowWizard我想OP的意思是让它看起来像只读的。就像文本框对小迟钝所做的那样appearance@SriramSakthivel是的。@Sinatr只是给它不同的背景?只读文本框获取
SystemColors.Control
color,您可以手动将其设置为您的复选框以获得类似的外观。我有种感觉,您只需共享一个自己使用的组件。谢谢测试了一下,效果很好。工具提示正常,样式可以调整
AutoSize
is@Sinatr事实上,它不是我自己使用的组件,我只是在尝试回答您的问题时编写的。我希望我的所有未来项目都将使用
WPF
,而不是
winforms
,但是如果团队使用