2
votes

I'm trying to implement an alt-tab like behaviour for our application. When the user presses ctrl-tab, a form pops up (using ShowDialog); when they press it again, it focuses the next control in the app's main form. When they release ctrl, the form is hidden.

Unfortunately, when that happens, focus is sent to a different control to the one that was focused. How can I prevent focus change when ShowDialog exits?

4
Which graphics library are you using? WinForms or WPF?Josh G
I added the winforms tab because of the multiple references to the ctrl-tab dialog and the app's main window as "forms".Greg D

4 Answers

2
votes

You could write a custom dialog that accepts the "to" focus control as a property.... then when exiting, you could set the focus to the "to" control.

0
votes

You may want to consider changing the way your dialog works. If I understand what you're saying, you could instead create a property on your CtrlTabDialog that would indicate which control should get focus. Then, when ShowDialog() exits, before you dispose the CtrlTabDialog form, you could read that property and set the focus appropriately from whatever code spawned the form initially.

0
votes

You should not use ShowDialog() for such purposes. Instead you should use Show() and Hide(), with control logic inside your main form.

You can also may want to prevent form activation at all, in this case, make Form descendant and override ShowWithoutActivation method.

You can also read my post here.

0
votes

I wrote a small app that shows how I would handle the behavior you describe.

I set up my main form with four controls (just buttons for this example, could be any controls you want). Then I set up another form which acts as the chooser. For this example, it just contains a ListBox with the control names in it. You could make something fancier. You could also pass in the currently focused control to have that one already selected in the list. I defaulted to the first control in the list.

I set up a public property on the MainForm called NextControl to hold the chosen control from the Chooser form. I also set up a List property to hold references to all the controls you want to be able to choose from. Using this method, ShowDialog should work fine, because the focus isn't set on the Next control until after that Dialog has exited.

MainForm:

using System.Collections.Generic;
using System.Windows.Forms;

namespace Tabber
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            ControlList = new List<Control>(new Control[] {button1, button2, button3, button4});
        }

        private List<Control> ControlList { get; set; }

        public Control NextControl { get; set; }

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Tab)
            {
                using (var chooseDialog = new Chooser(this, ControlList))
                {
                    if (chooseDialog.ShowDialog() == DialogResult.OK)
                    {
                        if (NextControl != null)
                        {
                            NextControl.Focus();
                        }
                    }
                }
            }
        }
    }
}

Chooser:

using System.Collections.Generic;
using System.Windows.Forms;

namespace Tabber
{
    public partial class Chooser : Form
    {
        public Chooser(MainForm sender, List<Control> controls)
        {
            Sender = sender;
            InitializeComponent();

            foreach (Control control  in controls)
            {
                listBox1.Items.Add(control);
            }
            listBox1.DisplayMember = "Name";
            listBox1.SetSelected(0, true);
        }

        private MainForm Sender { get; set; }

        private void Chooser_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Tab)
            {
                if (listBox1.SelectedIndex == listBox1.Items.Count - 1)
                {
                    listBox1.SetSelected(0, true);
                }
                else
                {
                    listBox1.SetSelected(listBox1.SelectedIndex + 1, true);
                }
                e.Handled = true;
            }
        }

        private void listBox1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                Sender.NextControl = (Control) listBox1.SelectedItem;
                DialogResult = DialogResult.OK;
                Close();
            }
        }
    }
}

You can modify this to suit your needs. It changed focus properly for me.