我正在构建一个通用应用程序,我想我在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;
}
}
答案 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");
}
这适用于两个平台。当然,这只是概念的证明,您可能希望在这里或那里进行空检查,但它可以工作。