0
votes

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);
        }
    });
}
1
Could you try to add the MenuFlyoutItem in UI-thread by call Dispatcher.Run() method?Nico Zhu - MSFT
@NicoZhu-MSFT This doesn't work.Seaky Lone
Do you means async void MenuFlyout_Opened cause flyout does not display?Nico Zhu - MSFT
Actually, it displays the MenuFlyoutItem after first right click. But on the first appearance of the MenuFlyout, it is empty. @NicoZhu-MSFTSeaky Lone
I found you have called async method in MenuFlyout_Opened method, could you try to call them with synchronization?Nico Zhu - MSFT

1 Answers

0
votes

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