C# 如何使Winform中的只读单选按钮看起来像标准单选按钮

3

简单的问题。 如果我在Winform项目中设置单选按钮为只读,它的外观(字体颜色)会变成浅灰色。当我将其启用属性设置为false时也是如此。

我该如何创建一个看起来像正常单选按钮的只读单选按钮? 因为这样你几乎看不到它。

谢谢


1
为了用户体验,不建议将单选按钮“看起来”像已启用,但实际上并没有启用。它变灰是有原因的。 - Johan
背景是灰色的...你无法阅读它。 - Mr. Toast
1
这个话题可能会对你有所帮助:https://dev59.com/GU_Sa4cB1Zd3GeqP_UwD - wmioduszewski
5个回答

3
将AutoCheck属性设置为false。

3
作为一种选项,您可以添加一个ReadOnly属性并重写OnClick, 仅当!ReadOnly时才调用base.OnClick(e):
using System;
using System.Windows.Forms;
public class MyRadioButton : RadioButton
{
    public bool ReadOnly { get; set; }
    protected override void OnClick(EventArgs e)
    {
        if (!ReadOnly)
            base.OnClick(e);
    }
}

太好了!谢谢。 - Mr. Toast
但是你仍然可以通过键盘来访问控制。 - undefined

1

通过删除单选按钮的文本并在其旁边添加标签来管理它。

不是最好的解决方案,但起作用了...


1
感谢PapaAtHome分享他的RadioButtonReadonly代码。
这里是相同的代码,但已转换为VB.Net:
Imports System
Imports System.Windows.Forms

Namespace RadioButtonControl
    ''' <summary>
    ''' 
    ''' Enables the user to show radio buttons in readonly mode.
    ''' </summary>
    ''' <remarks>
    ''' When visualstyle is enabled there is minimal feedback to the user about 'Readonly=true' (e.g.: not changing when hoovering over).
    '''
    ''' When visualstyle is not enabled there is no feedback to the user about 'Readonly=true'.
    ''' </remarks>
    Public Class RadioButtonReadonly
        Inherits RadioButton


        Private _readonly As Boolean = False

        Private _enabled As Boolean = True

        ''' <summary>
        ''' Radiobutton with Readonly attribute.
        ''' </summary>
        Public Sub New()
            Me.BaseEnabledCheck(Nothing, Nothing)
            AddHandler MyBase.EnabledChanged, AddressOf Me.BaseEnabledCheck
        End Sub

        ''' <summary>
        ''' Gets or sets a value indicating whether the control will respond to user interaction.
        ''' </summary>
        Public Property [Readonly] As Boolean
            Get
                Return Me._readonly
            End Get
            Set(value As Boolean)
                Dim flag As Boolean = Me._readonly <> value
                If flag Then
                    Me._readonly = value
                    Me.BaseEnabledCheck(Nothing, Nothing)
                End If
            End Set
        End Property

        ''' <summary>
        ''' Gets or sets a value indicating whether the control can respond to user interaction.
        ''' </summary>
        ''' <remarks>
        ''' Overruled to take away visualstyle behaviour.
        ''' </remarks>
        Public Property Enabled As Boolean
            Get
                Return Me._enabled
            End Get
            Set(value As Boolean)
                Dim flag As Boolean = Me._enabled <> value
                If flag Then
                    Me._enabled = value
                    Me.BaseEnabledCheck(Nothing, Nothing)
                End If
            End Set
        End Property

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.EnabledChanged event, force base.Enabled to always be true.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e">An System.EventArgs that contains the event data.</param>
        Private Sub BaseEnabledCheck(sender As Object, e As EventArgs)
            Dim [readonly] As Boolean = Me.[Readonly]
            If [readonly] Then
                Dim flag As Boolean = Not MyBase.Enabled
                If flag Then
                    MyBase.Enabled = True
                    MyBase.Invalidate()
                End If
            Else
                Dim flag2 As Boolean = Me.Enabled <> MyBase.Enabled
                If flag2 Then
                    MyBase.Enabled = Me.Enabled
                    MyBase.Invalidate()
                End If
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.Click event.
        ''' </summary>
        ''' <param name="e">An System.EventArgs that contains the event data.</param>
        Protected Overrides Sub OnClick(e As EventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnClick(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.ButtonBase.OnKeyUp(System.Windows.Forms.KeyEventArgs) event.
        ''' </summary>
        ''' <param name="kevent">A System.Windows.Forms.KeyEventArgs that contains the event data.</param>
        Protected Overrides Sub OnKeyDown(kevent As KeyEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnKeyDown(kevent)
            End If
        End Sub

        ''' <summary>
        ''' Occurs when a character. space or backspace key is pressed while the control has focus.
        ''' </summary>
        ''' <param name="e">A System.Windows.Forms.KeyPressEventArgs that contains the event data.</param>
        Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnKeyPress(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.ButtonBase.OnKeyUp(System.Windows.Forms.KeyEventArgs) event.
        ''' </summary>
        ''' <param name="kevent">A System.Windows.Forms.KeyEventArgs that contains the event data.</param>
        Protected Overrides Sub OnKeyUp(kevent As KeyEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnKeyUp(kevent)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.MouseUp event, draw the radio button in the checked or unchecked state.
        ''' </summary>
        ''' <param name="e">A System.Windows.Forms.MouseEventArgs that contains the event data.</param>
        Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseDown(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.MouseUp event, draw the radio button in the hot state.
        ''' </summary>
        ''' <param name="e"></param>
        Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseUp(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.MouseHover event, draw the radio button in the hot state.
        ''' </summary>
        ''' <param name="e">An System.EventArgs that contains the event data.</param>
        Protected Overrides Sub OnMouseHover(e As EventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseHover(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.OnMouseEnter(System.EventArgs) event, draw the radio button in the hot state.
        ''' </summary>
        ''' <param name="eventargs"></param>
        Protected Overrides Sub OnMouseEnter(eventargs As EventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseEnter(eventargs)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.OnMouseLeave(System.EventArgs) event, draw the radio button in the unpressed state.
        ''' </summary>
        ''' <param name="e">An System.EventArgs that contains the event data.</param>
        Protected Overrides Sub OnMouseLeave(e As EventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseLeave(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.MouseWheel event.
        ''' </summary>
        ''' <param name="e">A System.Windows.Forms.MouseEventArgs that contains the event data.</param>
        Protected Overrides Sub OnMouseWheel(e As MouseEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnMouseWheel(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.DragDrop event.
        ''' </summary>
        ''' <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        Protected Overrides Sub OnDragDrop(drgevent As DragEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnDragDrop(drgevent)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.DragEnter event.
        ''' </summary>
        ''' <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        Protected Overrides Sub OnDragEnter(drgevent As DragEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnDragEnter(drgevent)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.DragLeave event.
        ''' </summary>
        ''' <param name="e">An System.EventArgs that contains the event data.</param>
        Protected Overrides Sub OnDragLeave(e As EventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnDragLeave(e)
            End If
        End Sub

        ''' <summary>
        ''' Raises the System.Windows.Forms.Control.DragOver event.
        ''' </summary>
        ''' <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        Protected Overrides Sub OnDragOver(drgevent As DragEventArgs)
            Dim flag As Boolean = Not Me.[Readonly]
            If flag Then
                MyBase.OnDragOver(drgevent)
            End If
        End Sub

    End Class
End Namespace

1

旧问题使用旧代码,我知道。

最近我遇到了同样的问题。 原因:我想以一个漂亮可见的格式显示状态,但不允许用户更改该状态(故意或者意外)。 '禁用'格式不太易读或有吸引力。

我搜索了一些解决方案,这个线程排在首位。随着时间的推移,人们对这个主题进行了很多讨论,但仍然存在一些问题。

我为此创建了 RadioButtonReadonly,其中只读状态使用与启用状态相同的格式,但不允许用户更改任何设置。

我的思路是保护 base.Enabled 并替换它。如果在只读模式下,则拒绝来自用户的任何输入。

如果有人认为已启用未启用之间有不同的格式,那么我完全同意。但是,在某些情况下没有只读选项会导致令人烦恼的问题。

我找到了建议使用面板和覆盖层的方法,覆盖层是显示内容的图像。该图像显示所有面板成员处于启用模式,但该图像捕获所有单击事件。我尝试了这个方法,但得到的代码笨重且不灵活。

接下来,我尝试了RadioButtonReadonly,它具有一个额外的属性ReadOnly并覆盖了Enabled

ReadOnly=false 时,所有行为就像一般的Radiobutton

ReadOnly=true 时,显示布局与启用=false相同,但所有用户交互都会被静默忽略。

以下是我的 RadioButtonReadonly 代码和测试表格。

(注意:我从搜索中借用了一些代码和想法。不幸的是,我不记得在哪里看到的所有代码。使用覆盖层的最初想法来自 Hans Passant,他提出了一种静态解决方案,无法在运行时更改状态。我修改了它以跟踪更改。)

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace RadioButtonControl
{
    class Form1 : Form
    {
        RadioButtonReadonly RadioButton1 = new RadioButtonReadonly();
        RadioButtonReadonly RadioButton2 = new RadioButtonReadonly();
        RadioButton RadioButton3 = new RadioButton();
        RadioButton RadioButton4 = new RadioButton();

        Button button1 = new Button();
        Button button2 = new Button();
        Button button3 = new Button();

        public Form1() : base()
        {
            RadioButton1.Location = new Point(50, 50);
            RadioButton1.Size = new Size(100, 23);
            RadioButton1.Text = "Click 1ro";
            RadioButton1.Font = SystemFonts.IconTitleFont;
            Controls.Add(RadioButton1);

            RadioButton2.Location = new Point(50, 75);
            RadioButton2.Size = new Size(100, 23);
            RadioButton2.Text = "Click 2ro";
            RadioButton2.Font = SystemFonts.IconTitleFont;
            Controls.Add(RadioButton2);

            RadioButton3.Location = new Point(50, 100);
            RadioButton3.Size = new Size(100, 23);
            RadioButton3.Text = "Click 3";
            RadioButton3.Font = SystemFonts.IconTitleFont;
            Controls.Add(RadioButton3);

            RadioButton4.Location = new Point(50, 125);
            RadioButton4.Size = new Size(100, 23);
            RadioButton4.Text = "Click 4";
            RadioButton4.Font = SystemFonts.IconTitleFont;
            Controls.Add(RadioButton4);

            button1.Location = new Point(175, 231);
            button1.Size = new Size(105, 23);
            button1.Text = "Toggle Style";
            button1.Click += new EventHandler(this.button1_Click);
            Controls.Add(button1);

            button2.Location = new Point(175, 200);
            button2.Size = new Size(105, 23);
            button2.Text = "Toggle Enabled";
            button2.Click += new EventHandler(this.button2_Click);
            Controls.Add(button2);

            button3.Location = new Point(175, 169);
            button3.Size = new Size(105, 23);
            button3.Text = "Toggle Readonly";
            button3.Click += new EventHandler(this.button3_Click);
            Controls.Add(button3);

            Text = (Application.RenderWithVisualStyles) ? "Visual Styles Enabled" : "Visual Styles Disabled";
        }

        [STAThread]
        static void Main()
        {
            // If you do not call EnableVisualStyles below, then RadioButtonRenderer.DrawRadioButton automatically
            //  detects this and draws the radio button without visual styles.
            Application.EnableVisualStyles();

            Application.Run(new Form1());
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Application.VisualStyleState =
                Application.VisualStyleState ^
                VisualStyleState.ClientAndNonClientAreasEnabled;

            GroupBoxRenderer.RenderMatchingApplicationState = true;
            Text = (Application.RenderWithVisualStyles) ? "Visual Styles Enabled" : "Visual Styles Disabled";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            RadioButton1.Enabled = !RadioButton1.Enabled;
            RadioButton2.Enabled =  RadioButton1.Enabled;
            RadioButton3.Enabled =  RadioButton1.Enabled;
            RadioButton4.Enabled =  RadioButton1.Enabled;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            RadioButton1.Readonly = !RadioButton1.Readonly;
            RadioButton2.Readonly =  RadioButton1.Readonly;
        }
    }

    /// <summary>
    /// Enables the user to show radio buttons in readonly mode.
    /// </summary>
    /// <remarks>
    /// When visualstyle is enabled there is minimal feedback to the user about 'Readonly=true' (e.g.: not changing when hoovering over).
    /// 
    /// When visualstyle is not enabled there is no feedback to the user about 'Readonly=true'.
    /// </remarks>
    public class RadioButtonReadonly : RadioButton
    {
        /// <summary>
        /// Radiobutton with Readonly attribute.
        /// </summary>
        public RadioButtonReadonly()
        {
            BaseEnabledCheck(null, null);
            base.EnabledChanged += BaseEnabledCheck;
        }

        #region Readonly/Enabled
        /// <summary>
        /// Gets or sets a value indicating whether the control will respond to user interaction.
        /// </summary>
        public bool Readonly
        {
            get { return _readonly; }
            set
            {
                if (_readonly != value)
                {
                    _readonly = value;
                    BaseEnabledCheck(null, null);
                }
            }
        }
        bool _readonly = false;

        /// <summary>
        /// Gets or sets a value indicating whether the control can respond to user interaction.
        /// </summary>
        /// <remarks>
        /// Overruled to take away visualstyle behaviour.
        /// </remarks>
        public new bool Enabled
        {
            get { return _enabled; }
            set
            {
                if (_enabled != value)
                {
                    _enabled = value;
                    BaseEnabledCheck(null, null);
                }
            }
        }
        bool _enabled = true;

        /// <summary>
        /// Raises the System.Windows.Forms.Control.EnabledChanged event, force base.Enabled to always be true.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        private void BaseEnabledCheck(object sender, EventArgs e)
        {
            if (Readonly)
            {
                if (!base.Enabled)
                {
                    base.Enabled = true;
                    Invalidate();
                }
            }
            else
            {
                if (Enabled != base.Enabled)
                {
                    base.Enabled = Enabled;
                    Invalidate();
                }
            }
        }
        #endregion Readonly/Enabled

        #region User input handling
        /// <summary>
        /// Raises the System.Windows.Forms.Control.Click event.
        /// </summary>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnClick(EventArgs e)
        {
            if (!Readonly) base.OnClick(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.ButtonBase.OnKeyUp(System.Windows.Forms.KeyEventArgs) event.
        /// </summary>
        /// <param name="kevent">A System.Windows.Forms.KeyEventArgs that contains the event data.</param>
        protected override void OnKeyDown(KeyEventArgs kevent)
        {
            if (!Readonly) base.OnKeyDown(kevent);
        }

        /// <summary>
        /// Occurs when a character. space or backspace key is pressed while the control has focus.
        /// </summary>
        /// <param name="e">A System.Windows.Forms.KeyPressEventArgs that contains the event data.</param>
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (!Readonly) base.OnKeyPress(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.ButtonBase.OnKeyUp(System.Windows.Forms.KeyEventArgs) event.
        /// </summary>
        /// <param name="kevent">A System.Windows.Forms.KeyEventArgs that contains the event data.</param>
        protected override void OnKeyUp(KeyEventArgs kevent)
        {
            if (!Readonly) base.OnKeyUp(kevent);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.MouseUp event, draw the radio button in the checked or unchecked state.
        /// </summary>
        /// <param name="e">A System.Windows.Forms.MouseEventArgs that contains the event data.</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!Readonly) base.OnMouseDown(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.MouseUp event, draw the radio button in the hot state.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (!Readonly) base.OnMouseUp(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.MouseHover event, draw the radio button in the hot state.
        /// </summary>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnMouseHover(EventArgs e)
        {
            if (!Readonly) base.OnMouseHover(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.OnMouseEnter(System.EventArgs) event, draw the radio button in the hot state.
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnMouseEnter(EventArgs eventargs)
        {
            if (!Readonly) base.OnMouseEnter(eventargs);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.OnMouseLeave(System.EventArgs) event, draw the radio button in the unpressed state.
        /// </summary>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            if (!Readonly) base.OnMouseLeave(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.MouseWheel event.
        /// </summary>
        /// <param name="e">A System.Windows.Forms.MouseEventArgs that contains the event data.</param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (!Readonly) base.OnMouseWheel(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.DragDrop event.
        /// </summary>
        /// <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            if (!Readonly) base.OnDragDrop(drgevent);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.DragEnter event.
        /// </summary>
        /// <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        protected override void OnDragEnter(DragEventArgs drgevent)
        {
            if (!Readonly) base.OnDragEnter(drgevent);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.DragLeave event.
        /// </summary>
        /// <param name="e">An System.EventArgs that contains the event data.</param>
        protected override void OnDragLeave(EventArgs e)
        {
            if (!Readonly) base.OnDragLeave(e);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.DragOver event.
        /// </summary>
        /// <param name="drgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        protected override void OnDragOver(DragEventArgs drgevent)
        {
            if (!Readonly) base.OnDragOver(drgevent);
        }
        #endregion  User input handling
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接