loading page asynchronously

May 6, 2013 at 9:31 AM
Edited May 6, 2013 at 9:35 AM
I have the following code in my MainWindow.xaml:
        <mui:LinkGroup DisplayName="Result">
            <mui:LinkGroup.Links>
                <mui:Link DisplayName="Form" Source="/Pages/Result/Result.xaml" />
            </mui:LinkGroup.Links>
        </mui:LinkGroup>
The linked file (Result.xaml) looks like this:
    <Grid Style="{StaticResource ContentRoot}">
        <ScrollViewer HorizontalScrollBarVisibility="Auto" >
            <StackPanel MinWidth="200">
                <ContentControl Content="{Binding GeneratedUserControl}" HorizontalAlignment="Left" VerticalAlignment="Top" />
            </StackPanel>
        </ScrollViewer>
    </Grid>
The ContentControl in the Result.xaml binds to an UserControl which is generated at runtime. The UserControl Generation Process is triggered in the OnNavigatedTo from the IContent interface. Once, the generation and compilation is done i create an instance of the generated UserControl and assign it to the variable GeneratedUserControl which is the Binding target of the ContentControl in the Result.xaml.

It it working, but it freezes the GUI. Any idea how i can fix this?

EDIT:
This is what i already tried: (really bad code, don't do it like this!!)
        public void OnNavigatedTo(NavigationEventArgs e)
        {
            var vm = this.DataContext as MainViewModel;

            Thread FirstThread = new Thread(() => testMethod(vm));
            FirstThread.Start();
        }

        private void testMethod(MainViewModel vm)
        {
            vm.DisplayFlexFormCommand.Execute(new object());
        }
Problem is that the ViewModel is then used in another thread which means you can't navigate to any other page using this view model.
Coordinator
May 6, 2013 at 4:16 PM
You should wrap your long-run code in a task. Thread.Start works, but Task is recommended. For accessing the UI, you need to schedule a completion task on the UI thread. Something like this works:

Also, consider moving your logic from code-behind to a view model.
public void OnNavigatedTo(NavigationEventArgs e)
{
  // get the UI scheduler
  var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
  // start background task
  var task = Task.Factory.StartNew(() => OnWork());
  // start completion task on UI thread
  task.ContinueWith(t => OnWorkCompleted(t), scheduler);
}

private object OnWork()
{
  // TODO: do work, cannot access UI
  var result = new object();

  // return result 
  return result;
}

private void OnWorkCompleted(Task t)
{
  // handle completion, UI access allowed
  if (t.IsFaulted) {
    // TODO: handle error
  }
  else {
    var result = t.Result;

    // TODO: handle result
  } 
}
Sep 22, 2015 at 9:19 PM
Hi,

In this case, what should I do to make the default progress bar visible while the async operation is running?

Thank you,

Igor.