【发布时间】:2015-11-02 21:59:08
【问题描述】:
我正在构建我自己的带有列表选择的Flyout 控件,以便在Windows Phone 和Windows 桌面上使用它。与ListPickerFlyout 类不同,Flyout 类没有显示浮出控件的异步方法。
如何调用 ShowAt 方法异步并在弹出关闭后返回选定的值?
解决方案:
使用TaskCompletionSource<T> 可以实现异步行为(感谢AwaitableUI libary)。仍然困扰我的是我必须在构造函数中手动创建 ListView。如果我可以改用 XAML 并只分配一个模板,那就太好了,但我没有找到可行的方法。
public class ListPickerFlyout<T> : Flyout where T : class
{
private event EventHandler<object> ItemPicked;
public ListPickerFlyout(IEnumerable<T> items)
{
Placement = FlyoutPlacementMode.Full;
Opening += OnOpening;
Closed += OnClosed;
var listView = new ListView();
listView.SelectionMode = ListViewSelectionMode.None;
listView.IsItemClickEnabled = true;
listView.ItemClick += OnItemClick;
listView.DisplayMemberPath = "Name";
listView.SetBinding(ListView.ItemsSourceProperty, new Binding { Source = items });
Content = listView;
}
public async Task<T> ShowAsync()
{
this.ShowAt(Window.Current.Content as Frame);
var tcs = new TaskCompletionSource<T>();
EventHandler<object> eventHandler = null;
eventHandler = (s, e) =>
{
this.Closed -= eventHandler;
this.ItemPicked -= eventHandler;
tcs.SetResult(e as T);
};
this.Closed += eventHandler;
this.ItemPicked += eventHandler;
return await tcs.Task;
}
private void OnItemClick(object sender, ItemClickEventArgs e)
{
var selectedItem = e.ClickedItem as T;
var eventHandler = ItemPicked;
if (eventHandler != null)
eventHandler(this, selectedItem);
this.Hide();
}
private void OnOpening(object sender, object e)
{
var frame = Window.Current.Content as Frame;
var page = frame.Content as Page;
if (page != null)
page.BottomAppBar.Visibility = Visibility.Collapsed;
}
private void OnClosed(object sender, object e)
{
var frame = Window.Current.Content as Frame;
var page = frame.Content as Page;
if (page != null)
page.BottomAppBar.Visibility = Visibility.Visible;
}
}
【问题讨论】:
-
你试过
return new Task<Item>(() => ShowAt(Window.Current.Content as Frame));只是想不通,语法可能略有不同,因为我不确定 ShowAt 在选择后是否返回,但你可以做一个更复杂的任务在那里。 -
是的,我已经尝试过了,但它应该会在
Closed事件引发时返回。
标签: c# windows-runtime async-await winrt-async flyout