Libor Bešenyi (Solution Architect)
Sometimes it is necessary to select an item in the listbox/combox within the keyboard focus (for example, when the user returns from modal window managed by this listbox).
GUI selection is very simple, if we want to select data from enumeration, we can use this code:
public enum SameEnum { ValueA, Value2, Value3, Value4, AnotherValue } // SameEnum public MainWindow() { InitializeComponent(); ListBoxTest.ItemsSource = Enum.GetValues(typeof(SameEnum)).Cast<SameEnum>(); ListBoxTest.SelectedValue = SameEnum.Value4; ListBoxTest.Focus(); }
This will work, but when we push the arrow key (up/down), the item focus will be removed. We must select directly ListBoxItem for keyboard focus, not just value. ListBoxItem is embedded in ItemContainer, so we can hook event StatusChange (in run-time) – but we must remove the handler when it is done, so code is a bit horrible:
public static void SetValue<T>(Selector control, Func<T, bool> predicate) { var item = control.ItemsSource.OfType<T>().FirstOrDefault(predicate); if (item != null && (control as ListBox != null)) { EventHandler smernikNaEvent = null; smernikNaEvent = (object sender, EventArgs e) => { if ((control as ListBox).ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated) { int selectedIndex = (control as ListBox).SelectedIndex; if (selectedIndex < 0) control.ItemContainerGenerator.StatusChanged -= smernikNaEvent; else { ListBoxItem listBoxItem = (control as ListBox).ItemContainerGenerator.ContainerFromIndex(selectedIndex) as ListBoxItem; if (listBoxItem != null) { listBoxItem.Focus(); control.ItemContainerGenerator.StatusChanged += null; control.ItemContainerGenerator.StatusChanged -= smernikNaEvent; } // if } // else } // if }; control.ItemContainerGenerator.StatusChanged += smernikNaEvent; } // if control.SelectedValue = control.ItemsSource.OfType<T>().FirstOrDefault(predicate); } public MainWindow() { InitializeComponent(); ListBoxTest.ItemsSource = Enum.GetValues(typeof(SameEnum)).Cast<SameEnum>(); SetValue<SameEnum>(ListBoxTest, item => item == SameEnum.Value4); }
In .Net 3.5, there can be a problem with GUI focusing called from control.Focus(), so there is a workaround using this routine:
public static void Focus(this Dispatcher dispatcher, UIElement element) { dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(delegate() { element.Focus(); })); }
We must use this line:
Dispatcher.CurrentDispatcher.Focus(listBoxItem);
Instead of:
listBoxItem.Focus();