WinPhone 8.1 | Force xaml layout change

166 views Asked by At

I have a textbox that when the user presses enter, we perform an API call. However during this time I want to update the XAML layout to show a progressbar. However the layout update only takes place after the method has completed meaning that no progress bar is visible while we do the search.

We have overridden the OnKeyDown event to handle the user pressing enter.

Is there a way to force a XAML layout update during this method?

protected override void OnKeyDown(KeyRoutedEventArgs e)
    {
        if (e.Key == Windows.System.VirtualKey.Enter && (xaml_search_box.FocusState == Windows.UI.Xaml.FocusState.Pointer || xaml_search_box.FocusState == Windows.UI.Xaml.FocusState.Keyboard))
        {
            //We want to make the progressbar visible here
            xaml_search_progressbar.Visibility = Windows.UI.Xaml.Visibility.Visible         

            //collapse keyboard
            Windows.UI.ViewManagement.InputPane.GetForCurrentView().TryHide(); 

            string _query = xaml_search_box.Text;
            List<Task> tasks = new List<Task>();

            //Long web request
            Task t = Task.Run(() => APICall.BasicSearch(_query));
            tasks.Add(t);             
            Task.WaitAll(tasks.ToArray());

            m_results = APICall.m_basicsearch;
            xaml_search_results.ItemsSource = m_results;
            xaml_search_results_grid.ItemsSource = m_results;                
        }

        base.OnKeyDown(e);
        //Our layout is updated here, AFTER we have done the search making it pointless to show a loading bar
    }
3

There are 3 answers

1
Kevin Gosse On BEST ANSWER

You need to yield control to the UI thread to give it a chance to display the progress indicator. One convenient way to do that is to use the async/await keywords:

protected override async void OnKeyDown(KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.Enter && (xaml_search_box.FocusState == Windows.UI.Xaml.FocusState.Pointer || xaml_search_box.FocusState == Windows.UI.Xaml.FocusState.Keyboard))
    {
        //We want to make the progressbar visible here
        xaml_search_progressbar.Visibility = Windows.UI.Xaml.Visibility.Visible         

        //collapse keyboard
        Windows.UI.ViewManagement.InputPane.GetForCurrentView().TryHide(); 

        // Yield control to the UI thread
        await Task.Delay(10);

        string _query = xaml_search_box.Text;
        List<Task> tasks = new List<Task>();

        //Long web request
        Task t = Task.Run(() => APICall.BasicSearch(_query));
        tasks.Add(t);             
        Task.WaitAll(tasks.ToArray());

        m_results = APICall.m_basicsearch;
        xaml_search_results.ItemsSource = m_results;
        xaml_search_results_grid.ItemsSource = m_results;                
    }

    base.OnKeyDown(e);
    //Our layout is updated here, AFTER we have done the search making it pointless to show a loading bar
}

That said, you shouldn't block the UI thread while waiting for the tasks. You should use WhenAll instead of WaitAll:

await Task.WhenAll(tasks.ToArray());
0
glenebob On

You don't need the List. Simply await the Task.Run() call. The await will yield back to the UI thread and enable the progress bar to be shown. Very simple. You also need to make the event handler async.

await Task.Run(() => APICall.BasicSearch(_query));
0
trjast On

You need to make the overridden method async with protected override async void OnKeyDown(KeyRoutedEventArgs e), otherwise it will block the UI thread. You should also look into changing the APICall.BasicSearch method into an asynchronous method if possible, so you don't need to spin off Tasks like that and could instead just do something along the lines of m_results = await APICall.BasicSearch(_query);