很难从这个问题中得出一个问题.以下是一个非常简单的WinForms应用程序的一些视觉效果.

两个按钮,我将焦点()设置在Form_Showed中的Button1上.按键1确实有焦点,但你几乎看不出来.

Initial display on Form_Shown

如果我用Tab键切换到Button2,请注意它现在有一个附加的矩形,以帮助显示该按钮具有焦点.

After hitting tab

当窗体显示时,如何让按钮从一开始就带有相同的附加矩形显示,以便用户可以看到它或以其他方式显示按钮具有焦点?

Desired after Form_Shown

我在按钮上同时try 了Focus()和Select(),得到了相同的结果.谢谢!

    private void Form1_Load(object sender, EventArgs e)
    {
        button1.BackColor = Color.FromArgb(64, 64, 64);
        button1.ForeColor = SystemColors.HighlightText;

        button2.BackColor = Color.FromArgb(64, 64, 64);
        button2.ForeColor = SystemColors.HighlightText;
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        button1.Focus();
        //button1.Select();
    }

... UPDATE ...个 根据最初的 comments /反馈,焦点-矩形似乎正在按设计工作.我想我的问题是...我对按钮使用了深色(以匹配另一个产品/应用程序),按钮上的初始焦点()确实在它周围放置了一个边框,但它的 colored颜色 很浅,与表单混合在一起.如果我删除 colored颜色 并保留默认设置,您可以看到边框,并得到它具有焦点的提示……虽然仍然没有焦距矩形.

Plain vanilla buttons

所以,我想我需要重新考虑一下这个问题.我假设有焦点的按钮周围的边框不容易通过属性配置,我必须自定义绘制它?

推荐答案

确保第一个按钮是带有TabIndex=0的"One and Only"控件,这样它才能获得焦点,但这和被Tab键插入之间应该没有区别.

如果你 Select "定制油漆",你可以通过手动将所有的Button换成设计者.cs文件中的ButtonEx来使它的侵害性降到最低.然后,只需很少的代码,就可以拥有外焦点提示实心边框和虚线焦点矩形的设计时属性.

design time properties

tab action


class ButtonEx : Button
{
    public Color FocusRectangleColor
    {
        get => _focusRectangleColor;
        set
        {
            if (!Equals(_focusRectangleColor, value))
            {
                _focusRectangleColor = value;
                Refresh();
            }   
        }
    }
    Color _focusRectangleColor = Color.Red;

    public Color FocusCueColor
    {
        get => _focusCueColor;
        set
        {
            if (!Equals(_focusCueColor, value))
            {
                _focusCueColor = value;
                Refresh();
            }
        }
    }
    Color _focusCueColor = default;

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (Enabled && Focused && (MouseButtons == MouseButtons.None))
        {
            if (FocusRectangleColor != default)
            {
                using (Pen dottedPen = new Pen(FocusRectangleColor, 2f))
                {
                    dottedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                    Rectangle focusRect = this.ClientRectangle;
                    focusRect.Inflate(-12, -12);
                    e.Graphics.DrawRectangle(dottedPen, focusRect);
                }
            }
            if (FocusCueColor != default)
            {
                using (Pen cuePen = new Pen(FocusCueColor, FlatAppearance.BorderSize))
                {
                    Rectangle focusRect = this.ClientRectangle;
                    focusRect.Inflate(-2, -2);
                    e.Graphics.DrawRectangle(cuePen, focusRect);
                }
            }
        }
    }
}

Testing

在以下情况下,编写的代码应正确导航:

  • [Tab]键用于导航.
  • 鼠标用于点击按钮.
  • 以编程方式调用button.Focus().
  • 从当前聚焦的控件调用SelectNextControl().
  • ActiveControl以编程方式设置.

为了举止得体:

  • 需要正确设置TabOrder个控件
  • 对于要标记的控件,TabStop属性应为true,否则为False.
  • 该表单必须处于活动状态.
  • 应该具有焦点的按钮必须具有最低的制表符索引.

Testbench

下面是我用TabIndex的值测试这个答案的代码,如VS Menu\View\Tab Order中所示.Clone.使用组合框,可以 Select 定时器模式,以在上面列表中导航的三个"程序化"选项之间循环.

tab order

public partial class MainForm : Form
{
    enum TimerMode { None, FocusNext, SelectNext, NextActive }
    public MainForm()
    {
        InitializeComponent();
        comboBoxTimers.Items.AddRange(Enum.GetValues(typeof(TimerMode)).OfType<object>().ToArray());
        comboBoxTimers.SelectedIndex = 0;
        comboBoxTimers.SelectionChangeCommitted += async(sender, e) =>
        {
            _timerMode = TimerMode.None;
            await _busy.WaitAsync();
            _timerMode = (TimerMode)(comboBoxTimers.SelectedItem ?? TimerMode.None);
            BeginInvoke(()=>ActiveControl = button1);
            string name;
            switch (_timerMode)
            {
                case TimerMode.FocusNext:
                    do
                    {
                        await Task.Delay(1000);
                        if (!comboBoxTimers.DroppedDown)
                        {
                            name = ActiveControl?.Name ?? string.Empty;
                            switch (name)
                            {
                                case nameof(button1): button2.Focus(); break;
                                case nameof(button2): button3.Focus(); break;
                                default: case nameof(button3): button1.Focus(); break;
                            }
                        }
                    } while (_timerMode == TimerMode.FocusNext);
                    _busy.Release();
                    break;
                case TimerMode.SelectNext:
                    do
                    {
                        await Task.Delay(1000);
                        if (!comboBoxTimers.DroppedDown)
                        {
                            if (ActiveControl != null) SelectNextControl(
                                ctl: ActiveControl,
                                forward: true,
                                tabStopOnly: true,
                                nested: true,
                                wrap: true
                            );
                        }
                    } while (_timerMode == TimerMode.SelectNext);
                    _busy.Release();
                    break;
                case TimerMode.NextActive:
                    do
                    {
                        await Task.Delay(1000);
                        if (!comboBoxTimers.DroppedDown)
                        {
                            name = ActiveControl?.Name ?? string.Empty;
                            switch (name)
                            {
                                case nameof(button1): ActiveControl = button2; break;
                                case nameof(button2): ActiveControl = button3; break;
                                default: case nameof(button3): ActiveControl = button1; break;
                            }
                        }
                    } while (_timerMode == TimerMode.NextActive);
                    _busy.Release();
                    break;
            }
        };
    }
    TimerMode _timerMode = TimerMode.None;
    SemaphoreSlim _busy = new SemaphoreSlim(1, 1);
}

Csharp相关问答推荐

如何在实体框架中添加包含列表?

Blazorise折线图仅绘制数据集的一部分

C#和ASP.NET核心标识:提高GetUserAsync调用的性能

C#DateTime.ParseExact不使用特定日期

如何在我的C#应用程序中设置带有reactjs前端的SignalR服务器?

在DoubleClick上交换DataGridViewImageColumn的图像和工具提示

使用System.Text.Json进行序列化时发生StackOverflow异常

C#LINQ子字符串

如何在同一成员上组合[JsonPropertyName]和[ObservableProperty]?

在使用AWS SDK for.NET时,如何判断S3是否已验证我的对象的校验和?

如何在mediatr命令中访问HttpContext而不安装弃用的nuget包

在.NET8中如何反序列化为私有字段?

仅在Blazor Web App中覆盖生产的基本路径(.NET8中的_Hosts.cshtml文件功能?)

使用免费的DotNet库从Azure函数向Azure文件共享上的现有Excel文件追加行

C#11/.NET 7-判断&t;值类型>;后的可为空性行为

ASP.NET Core 7 MVC错误CS1061不包含的定义

在静态比较器类中调试函数

使用文本模式按坐标显示图形

这里应该使用什么样的数据 struct ?

升级到 MySQL ODBC 连接器 8.1 后简单存储过程命令失败