Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Focussing a WebView after a MessageDialog is closed

I've got a contentEditable based editor within a WebView in my Windows Store app. Certain keyboard shortcuts and buttons can cause a MessageDialog to open. When this dialog is dismissed, the editor no longer has focus. I've tried setting focus every way I know, and it won't work. Here's a sample app.

MainPage.xaml

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <WebView x:Name="Editor" Margin="200"></WebView>
    </Grid>

    <Page.BottomAppBar>
        <CommandBar x:Name="CommandBar_Editor" Visibility="Visible">
            <AppBarButton Label="Debug" Icon="Setting">
                <AppBarButton.Flyout>
                    <MenuFlyout>
                        <MenuFlyoutItem Text="show dialog, then focus" Click="MenuFlyoutItem_Click_1"/>
                    </MenuFlyout>
                </AppBarButton.Flyout>
            </AppBarButton>
        </CommandBar>
    </Page.BottomAppBar>
</Page>

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        Editor.NavigateToString("<script type='text/javascript'>function focus_please(){ document.getElementById('editor').focus(); }</script><div id='editor' contentEditable='true'>It was the best of times, it was the worst of times</div>");
    }

    private async void MenuFlyoutItem_Click_1(object sender, RoutedEventArgs e)
    {
        MessageDialog dialog = new MessageDialog("this should set focus to editor on close", "test");
        UICommand okCommand = new UICommand("OK");
        dialog.Commands.Add(okCommand);

        IUICommand response = await dialog.ShowAsync();

        if (response == okCommand)
        {
            Editor.Focus(FocusState.Programmatic);
            // I've also tried:
            // FocusState.Keyboard
            // FocusState.Pointer 
            // FocusState.Unfocused

            // this calls JS within the HTML to focus the contentEditable div
            await Editor.InvokeScriptAsync("focus_please", null);
        }
    }
}

It seems to me that the WebView is focussed, but not the HTML content within

Update:

Updated my example to add in Bryan's code from the answer below, but it's still not working.

Note After the MessageDialog is dismissed, if I press Tab twice the editor becomes active again.

Update 2:

Bryan's answer below does work when using the touch screen to navigate. However when using mouse and keyboard, the contentEditable element does not focus. I've put a bounty on this looking for a solution which allows the item to be focussed either when using the touch screen or the mouse / keyboard combo

like image 873
roryok Avatar asked Sep 10 '14 11:09

roryok


1 Answers

If you set focus state in C# the correct parameter is always FocusState.Programmatic. The other values are there for the purpose of reading the current focus value.

Sounds like you are trying to focus the control within the webview instead of the actual webview. The C#/XAML side of things will not know about the content within the webview. For that you will have to invoke javascript which will know about the controls.

Here is a link to MSDN on your scenerio. WebView.Focus method

Edit: According to the article, the WebView must get focus first, then the javascript invoked.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        string html = "<html><head><script type='text/javascript'>function focusContent()" +
                      " {if(window.location.hash != '#TaleofTwoCities'){ window.location.hash = '#TaleofTwoCities';}};" +
                      "</script></head><body><div id='TaleofTwoCities' contentEditable='true'>It was the best of times, it was the worst of times</div></body></html>";

        Editor.NavigateToString(html);
    }

    private async void MenuFlyoutItem_Click_1(object sender, RoutedEventArgs e)
    {
        MessageDialog dialog = new MessageDialog("this should set focus to editor on close", "test");
        UICommand okCommand = new UICommand("OK");
        dialog.Commands.Add(okCommand);

        IUICommand response = await dialog.ShowAsync();

        if (response == okCommand)
        {
            await Window.Current.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                Editor.Focus(FocusState.Programmatic);
            });
            await Window.Current.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                Editor.InvokeScript("focusContent", null);
            });
        }
    }

Here's my XAML

<Page x:Class="StackOverflow.WebViewFocus"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:StackOverflow"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel VerticalAlignment="Center"><WebView Width="300"
             x:Name="Editor"
             Height="300"></WebView>
        <Button Click="MenuFlyoutItem_Click_1">focus</Button>
    </StackPanel>

</Grid>
<Page.BottomAppBar>
    <CommandBar x:Name="CommandBar_Editor"
                Visibility="Visible">
        <AppBarButton Label="Debug"
                      Icon="Setting">
            <AppBarButton.Flyout>
                <MenuFlyout>
                    <MenuFlyoutItem Text="show dialog, then focus"
                                    Click="MenuFlyoutItem_Click_1" />
                </MenuFlyout>
            </AppBarButton.Flyout>
        </AppBarButton>
    </CommandBar>
</Page.BottomAppBar>
</Page>
like image 169
Bryan Stump Avatar answered Nov 05 '22 19:11

Bryan Stump