正在进行后台工作时弹出菜单中的错误?

时间:2015-04-03 14:30:37

标签: c# xaml windows-phone-8.1 win-universal-app

我正在构建一个通用应用程序,我想我在Windows Phone 8.1 PopupMenu控件中发现了一个错误。我已经能够用一小段代码重现它。它在Windows 8上运行正常,但在Windows Phone 8.1上运行不正常。

每当我从一个按钮内创建一个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;
    }
}

1 个答案:

答案 0 :(得分:0)

使用MenuFlyout怎么样?

假设您在页面的代码隐藏中定义了它,并将TaskCompletionSource包装起来以使其显示为等待:

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是可以等待的并且实现如下:

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");
}

这适用于两个平台。当然,这只是概念的证明,您可能希望在这里或那里进行空检查,但它可以工作。