By invoking Task.Run you broke your association(SynchronizationContext) with the GUI thread (or WPF Dispatcher) and lost most of the async/await 'goodness'.
Why not use an async void event handler and just come back to the SynchronizationContext(GUI Thread/Dispatcher) for each step?
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    while (true)
    {
        string result = await LoadNextItem();
        lbl1.Content = result;
    }
}
private static int ir11 = 0;
Task<string> LoadNextItem()
{
    await Task.Delay(1000); // placeholder for actual async work
    ir11++;
    return "aa " + ir11;
}
Or if you really want to separate the state machine for the 'on-going' operations, try passing an IProgress<T> (the default impl. Progress<T> or specifically Progress<string> should work great in this case).  See this article by @Stephen Cleary
His example is very close to what you stated in the question.  I've copied it here for SO independence.
public async void StartProcessingButton_Click(object sender, EventArgs e)
{
  // The Progress<T> constructor captures our UI context,
  //  so the lambda will be run on the UI thread.
  var progress = new Progress<int>(percent =>
  {
    textBox1.Text = percent + "%";
  });
  // DoProcessing is run on the thread pool.
  await Task.Run(() => DoProcessing(progress));
  textBox1.Text = "Done!";
}
public void DoProcessing(IProgress<int> progress)
{
  for (int i = 0; i != 100; ++i)
  {
    Thread.Sleep(100); // CPU-bound work
    if (progress != null)
      progress.Report(i);
  }
}
Edit: I must admit, while Progress<T> is a nice abstraction, in this case it is just going to fall down to Dispatcher.Invoke as @Pamparanpa suggested.