Seaky Lone
Seaky Lone

Reputation: 1031

UWP Async MenuFlyout opening/opened

I need to set my MenuFlyout in a programmatical way. However, I notice that with the async code added to my function, the MenuFlyout doesn't show its items unless I right click the item for the second time. How can I set my MenuFlyout in an async way?

private async void MenuFlyout_Opened(object sender, object e)
{
    var flyout = sender as MenuFlyout;
    Music music = flyout.Target.DataContext as Music;
    if (await Helper.FileNotExist(music.Path))
    {
        if (Removable)
        {
            flyout.Items.Clear();
            flyout.Items.Add(MenuFlyoutHelper.GetRemovableMenuFlyoutItem(music, this));
        }
        else
        {
            Helper.ShowAddMusicResultNotification(music.Name);
        }
        return;
    }
    if (Removable) MenuFlyoutHelper.SetRemovableMusicMenu(sender, this);
    else MenuFlyoutHelper.SetMusicMenu(sender, this);
    if (AllowReorder)
    {
        var item = new MenuFlyoutItem()
        {
            Text = Helper.Localize("Move To Top"),
            Icon = new SymbolIcon(Symbol.Upload)
        };
        item.Click += (s, args) =>
        {
            MediaHelper.MoveMusic(music.Index, 0);
        };
        flyout.Items.Add(item);
    }
}

One way is to avoid using async code in such functions and to check if file exists in the Click event of the items. But I have too many items. I think this is a bad idea.

This code works properly:

private void OpenMusicMenuFlyout(object sender, object e)
{
    if (Removable) MenuFlyoutHelper.SetRemovableMusicMenu(sender, this);
    else MenuFlyoutHelper.SetMusicMenu(sender, this);
    if (AllowReorder)
    {
        var flyout = sender as MenuFlyout;
        var item = new MenuFlyoutItem()
        {
            Text = Helper.Localize("Move To Top"),
            Icon = new SymbolIcon(Symbol.Upload)
        };
        item.Click += (s, args) =>
        {
            Music music = (s as MenuFlyoutItem).DataContext as Music;
            MediaHelper.MoveMusic(music.Index, 0);
        };
        flyout.Items.Add(item);
    }
}

Code with Dispatcher.RunAsync:

private async void OpenMusicMenuFlyout(object sender, object e)
{
    var flyout = sender as MenuFlyout;
    Music music = flyout.Target.DataContext as Music;
    if (await Helper.FileNotExist(music.Path))
    {
        if (Removable)
        {
            flyout.Items.Clear();
            flyout.Items.Add(MenuFlyoutHelper.GetRemovableMenuFlyoutItem(music, this));
        }
        else
        {
            Helper.ShowAddMusicResultNotification(music.Name);
        }
        return;
    }
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
    {

        if (Removable) MenuFlyoutHelper.SetRemovableMusicMenu(sender, this);
        else MenuFlyoutHelper.SetMusicMenu(sender, this);
        if (AllowReorder)
        {
            var item = new MenuFlyoutItem()
            {
                Text = Helper.Localize("Move To Top"),
                Icon = new SymbolIcon(Symbol.Upload)
            };
            item.Click += (s, args) =>
            {
                MediaHelper.MoveMusic(music.Index, 0);
            };
            flyout.Items.Add(item);
        }
    });
}

Upvotes: 0

Views: 404

Answers (1)

Nico Zhu
Nico Zhu

Reputation: 32775

Great question, for the testing, if we call async function in above OpenMusicMenuFlyout event handler, MenuFlyout Add operation will be interrupted, and UI rendering will be canceled. For above scenario, the better way is make Flyout as ContextFlyout content then use ListView to replace MenuFlyout. For more please check the following.

<SwipeControl>
    <SwipeControl.ContextFlyout>
        <Flyout Opening="OpenMusicMenuFlyout">
            <ListView>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}"/>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Flyout>
    </SwipeControl.ContextFlyout>
</SwipeControl>

Code Behind

private async void OpenMusicMenuFlyout(object sender, object e)
{
    var items = new ObservableCollection<string>() { "One", "Two", "Three" };
    var flyout = sender as Flyout;
    var menu =  flyout.Content as ItemsControl;
    await TestMetod();
    menu.ItemsSource = items;
}

Upvotes: 0

Related Questions