views:

654

answers:

4

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?

+1  A: 

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.

JosephStyons
A: 

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.

Greg D
A: 

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.

arbiter
A: 

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.

jomtois