Sunday, September 19, 2010

[Silverlight] ChildWindow focus bugs, oh my!

Another day of programming, another bug in silverlight to work around. When I'm not working around bugs, I'm crazy productive however.

The issue today is key focus, in particular with ChildWindow. This class allows you to place modal dialogs up with a minimal of fuss. The problem is that for some reason they weren't getting keyboard focus correctly. This is a big problem when you want your entire game to be able to be run from the keyboard alone.

Here is my solution (with help from a friend):
public ChildWindowNoFade ParentWindow;

        public ChildWindowNoFade()
        {
            this.DefaultStyleKey = typeof(ChildWindowNoFade);
            this.Loaded += new RoutedEventHandler(ChildWindowNoFade_Loaded);
            this.Closing += new EventHandler<System.ComponentModel.CancelEventArgs>(ChildWindowNoFade_Closing);
        }

        void ChildWindowNoFade_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Dispatcher.BeginInvoke(() =>
            {
                if (ParentWindow != null)
                {
                    ParentWindow.Focus();
                    if (ParentWindow.InitialFocusItem != null)
                        ParentWindow.InitialFocusItem.Focus();
                }
            });
        }

        void ChildWindowNoFade_Loaded(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(() => 
            {
                Focus();
                if (InitialFocusItem != null)
                    InitialFocusItem.Focus();
            });
        }

        protected abstract Control InitialFocusItem
        {
            get;
        }

Roughly, I'm creating a base class that hooks into loading and closing of windows. It fixes up the focus problems in cases of stacked modal dialog (where ParentWindow is non-null).

A few other notes:
  • Some child windows act funny with keyboard focus if they don't have controls in them and/or they don't have IsTabStop="True" TabIndex="1" set on the window
  • System.Windows.Browser.HtmlPage.Plugin.Focus();    If you call this guy on the creation of your root object will give your application focus.

No comments: