2015-04-03 46 views
1

我正在構建一個通用應用程序,我想我在Windows Phone 8.1 PopupMenu控件中發現了一個錯誤。我已經能夠用一小段代碼重現它。它在Windows 8上正常工作,但在Windows Phone 8.1上無法正常工作。當後臺工作開始時,PopupMenu中的錯誤?

每當我從一個按鈕中創建一個PopupMenu時,在運行後臺任務時,它不會從ShowFromSelectionAsync()返回?爲什麼? 相同的代碼在Windows 8上工作。

我的應用程序很多後臺工作正在完成,所以控件無法在手機上正常工作了。任何建議如何解決這個問題?

我有一個MainPage.xaml中:

<Page 
    x:Class="PopupMenuBugPhone.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:PopupMenuBugPhone" 
    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> 
      <Button Content="Test Bug" Click="Button_Click" /> 
     </StackPanel> 
    </Grid> 
</Page> 

MainPage.xaml.cs中:

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

    private async void Button_Click(object sender, RoutedEventArgs e) 
    { 
     var frameworkElement = sender as FrameworkElement; 


     var task = SimulateBackgroundWork();  // COMMENT THIS TO MAKE IT WORK ON PHONE!!! 

     var menu = new PopupMenu(); 
     var сmdOption1 = new UICommand("Option1"); 
     var cmdOption2 = new UICommand("Option2"); 
     menu.Commands.Add(сmdOption1); 
     menu.Commands.Add(cmdOption2); 

     // We don't want to obscure content, so pass in a rectangle representing the sender of the context menu event. 
     var chosenCommand = await menu.ShowForSelectionAsync(frameworkElement.GetElementRect()); 
     if (chosenCommand == null) // The command is null if no command was invoked. 
     { 
      await new MessageDialog("No choice").ShowAsync(); 
     } 
     else 
     { 
      await new MessageDialog("Choice: " + chosenCommand.Label).ShowAsync(); 
     } 

     await task;  // COMMENT THIS TO MAKE IT WORK ON PHONE!!! 
    } 

    private Task SimulateBackgroundWork() 
    { 
     var t = Task.Run(() => 
     { 
      var dt = DateTime.Now; 
      // Do some dummy processing loop 
      while (DateTime.Now < dt.AddSeconds(300)) 
      { 
       ; 
      } 
     }); 

     return t; 
    } 
} 

回答

0

如何使用MenuFlyout?

讓我們假設你在頁面的代碼隱藏定義它,隨着TaskCompletionSource把它包起來,使顯示awaitable:

MenuFlyout flyout = new MenuFlyout(); 
TaskCompletionSource<string> tcs; 

然後在點擊鏈接,你可以這樣做:

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    var frameworkElement = sender as FrameworkElement; 

    var task = SimulateBackgroundWork(); 

    flyout.Closed += flyout_Closed; 

    var mf1 = new MenuFlyoutItem { Text = "Option1" }; 
    var mf2 = new MenuFlyoutItem { Text = "Option2" }; 

    mf1.Click += mf_Click; 
    mf2.Click += mf_Click; 

    flyout.Items.Clear(); 
    flyout.Items.Add(mf1); 
    flyout.Items.Add(mf2); 

    await ShowMenuFlyout(sender as FrameworkElement); 

    await task; 
} 

ShowMenuFlyout是awaitable像這樣實現的:

public Task<string> ShowMenuFlyout(FrameworkElement sender) 
{ 
    tcs = new TaskCompletionSource<string>(); 

    flyout.ShowAt(sender as FrameworkElement); 

    return tcs.Task; 
} 

而且事件處理程序只需執行以下操作:

async void mf_Click(object sender, RoutedEventArgs e) 
{ 
    flyout.Closed -= flyout_Closed; 

    await new MessageDialog("Choice: " + (sender as MenuFlyoutItem).Text).ShowAsync(); 

    tcs.SetResult((sender as MenuFlyoutItem).Text); 
} 

async void flyout_Closed(object sender, object e) 
{ 
    flyout.Closed -= flyout_Closed; 

    await new MessageDialog("No choice").ShowAsync(); 

    tcs.SetResult("No choice"); 
} 

這適用於兩種平臺。當然,這只是概念的證明,你可能想要在這裏或那裏有一個空檢查,但它的工作原理。

+0

太好了!這看起來不錯 – JeroenB 2015-05-04 20:48:24