很难从这个问题中得出一个问题.以下是一个非常简单的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相关问答推荐

.NET通过版本自动增量设置包版本

向类注入一个工厂来创建一些资源是一个好的实践吗?

什么是通过反射创建类的泛型接口方法的正确方法?

是否可以使用EF—Core进行临时部分更新?

由于POST中的应用程序/JWT,出现不支持的内容类型异常

为基本审计设置Audit.EntityFramework.Core

NET8 MAUI并部署到真实设备上进行测试

按需无缝转码单个HLS数据段

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

如何更改新创建的实例的变量?

在扩展方法中,IEnumerable<;T>;不会转换为IEumerable<;T&>

.NET Google Workspace API获取错误CS0266

如何对特定异常使用Polly重试机制?

当我手动停止和关闭系统并打开时,Windows服务未启动

WPF如何获取有关从一个视图模型更改另一个视图模型的信息

在C#和HttpClient中使用REST API

在Visual Studio 2022中查找Xamarin模板时遇到问题

处理方法内部过滤与外部过滤

CsvHelper在第二次迭代时抛出System.ObjectDisposedException

从具有泛型类型约束的类继承-Blazor