2013-12-02 4 views

ответ

11

Да.

Я собрал простое решение для разработчиков, которые желают этой функциональности. Он использует прикрепленное свойство для идентификации ItemsSource и ItemTemplate для элемента управления вылетом. Если разработчик решит использовать MenuFlyoutItem или что-то еще, это зависит от них.

Вот вложенное свойство:

public class BindableFlyout : DependencyObject 
{ 
    #region ItemsSource 

    public static IEnumerable GetItemsSource(DependencyObject obj) 
    { 
     return obj.GetValue(ItemsSourceProperty) as IEnumerable; 
    } 
    public static void SetItemsSource(DependencyObject obj, IEnumerable value) 
    { 
     obj.SetValue(ItemsSourceProperty, value); 
    } 
    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.RegisterAttached("ItemsSource", typeof(IEnumerable), 
     typeof(BindableFlyout), new PropertyMetadata(null, ItemsSourceChanged)); 
    private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { Setup(d as Windows.UI.Xaml.Controls.Flyout); } 

    #endregion 

    #region ItemTemplate 

    public static DataTemplate GetItemTemplate(DependencyObject obj) 
    { 
     return (DataTemplate)obj.GetValue(ItemTemplateProperty); 
    } 
    public static void SetItemTemplate(DependencyObject obj, DataTemplate value) 
    { 
     obj.SetValue(ItemTemplateProperty, value); 
    } 
    public static readonly DependencyProperty ItemTemplateProperty = 
     DependencyProperty.RegisterAttached("ItemTemplate", typeof(DataTemplate), 
     typeof(BindableFlyout), new PropertyMetadata(null, ItemsTemplateChanged)); 
    private static void ItemsTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { Setup(d as Windows.UI.Xaml.Controls.Flyout); } 

    #endregion 

    private static async void Setup(Windows.UI.Xaml.Controls.Flyout m) 
    { 
     if (Windows.ApplicationModel.DesignMode.DesignModeEnabled) 
      return; 
     var s = GetItemsSource(m); 
     if (s == null) 
      return; 
     var t = GetItemTemplate(m); 
     if (t == null) 
      return; 
     var c = new Windows.UI.Xaml.Controls.ItemsControl 
     { 
      ItemsSource = s, 
      ItemTemplate = t, 
     }; 
     var n = Windows.UI.Core.CoreDispatcherPriority.Normal; 
     Windows.UI.Core.DispatchedHandler h =() => m.Content = c; 
     await m.Dispatcher.RunAsync(n, h); 
    } 
} 

И вот использование образца.

<Page.BottomAppBar> 
    <CommandBar> 
     <AppBarButton Label="AppBarButton"> 
      <AppBarButton.Flyout> 
       <Flyout local:BindableFlyout.ItemsSource="{Binding MenuItems}"> 
        <local:BindableFlyout.ItemTemplate> 
         <DataTemplate> 
          <MenuFlyoutItem Text="{Binding Text}" /> 
         </DataTemplate> 
        </local:BindableFlyout.ItemTemplate> 
       </Flyout> 
      </AppBarButton.Flyout> 
      <AppBarButton.Icon> 
       <SymbolIcon/> 
      </AppBarButton.Icon> 
     </AppBarButton> 
    </CommandBar> 
</Page.BottomAppBar> 

Я буду поддерживать этот код here.

выглядит так:

enter image description here

Я надеюсь, что это поможет вам.

Удачи!

+0

Я использую ваш пример кода, но я нахожу, что меню больше не отменяет себя после щелчка элемента. Есть идеи? – krisdyson

+0

О, я думаю, это может быть потому, что это вылет, а не MenuFlyout, я посмотрю, смогу ли я что-то сделать из вашего блога. спасибо – krisdyson

+0

Использование поведения ChangePropertyAction Blend можно просто установить для свойства Flyout.IsOpen значение false при щелчке по элементу MenuItem. Имеют смысл? Конечно, вы могли бы сделать это и в коде. В любом случае. У вас также может быть свойство MenuOpen в ViewModel, если вы хотите сделать это там. Множество вариантов. –

0

Это работает для меня. Надеюсь, я ничего не пропустил.

class CustomCommand : ICommand 
    { 
     public ICommand CommandObject { get { return this; } } 
     public String CommandName { get; private set; } 

     public CustomCommand(String name):base() 
     { 
      this.CommandName = name; 
     } 
    } 

    class EncapsulateOrDecoratorObjectForContextMenu 
    { 
     private object baseObject; 
     // chaned properties to the baseObject 

     public List<CustomCommand> AvailableCommands { get; set; } 

     public EncapsulateOrDecoratorObjectForContextMenu(object baseObject, List<CustomCommand> commands) 
     { 
      this.baseObject = baseObject; 
      this.AvailableCommands = commands; 
     } 

    } 

    class SomePage: Page 
    { 
     private MenuFlyout mFlyout; 

     public SomePage() 
     { 
      // I don't know why, but it's to be here... unless UI/design go crazy 
      this.mFlyout = new MenuFlyout(); 
     } 

     private void Grid_Holding(object sender, HoldingRoutedEventArgs e) 
     { 
      if (e.OriginalSource is FrameworkElement && (e.OriginalSource as FrameworkElement).DataContext is EncapsulateOrDecoratorObjectForContextMenu) 
      { 
       // Only the property is 'readonly', not the List<menuItem> itself, so... 
       this.mFlyout.Items.Clear(); 

       MenuFlyoutItem menuItem; 
       foreach (CustomCommand command in ((e.OriginalSource as FrameworkElement).DataContext as EncapsulateOrDecoratorObjectForContextMenu).AvailableCommands) 
       { 
        menuItem = new MenuFlyoutItem(); 
        menuItem.Text = command.CommandName; 
        menuItem.Command = command.CommandObject; 

        this.mFlyout.Items.Add(menuItem); 
       } 

       FrameworkElement senderElement = sender as FrameworkElement; 
       this.mFlyout.ShowAt(senderElement); 
      } 
     } 
    } 
0

Несмотря на то, что первоначальный вопрос был задан много лет назад, я отправлю решение, которое я нашел, поскольку кто-то может найти его полезным.

Решение Джерри имеет серьезный недостаток: MenuFlyout не закрывается, когда вы нажимаете на элемент, и мне было очень трудно это сделать, поскольку кажется, что (почти?) Невозможно получить ссылку на Вылет изнутри DataTemplate, чтобы закрыть его.

Я пришел к этому решению, что подклассы MenuFlyout:

public class BindableFlyout : MenuFlyout 
{ 
    public ICollection<ContextMenuCommand> ItemsSource 
    { 
     get { return (ICollection<ContextMenuCommand>)GetValue(ItemsSourceProperty); } 
     set { SetValue(ItemsSourceProperty, value); } 
    } 

    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.Register("ItemsSource", typeof(ICollection<ContextMenuCommand>), typeof(BindableFlyout), new PropertyMetadata(null, (DependencyObject o, DependencyPropertyChangedEventArgs args) => 
     { 
      Setup(o as BindableFlyout); 
     } 
    )); 

    private static async void Setup(BindableFlyout menuFlyout) 
    { 
     if (Windows.ApplicationModel.DesignMode.DesignModeEnabled) 
      return; 
     if (menuFlyout.ItemsSource == null) 
      return; 

     await menuFlyout.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,() => 
     { 
      menuFlyout.Items.Clear(); 
      foreach (var menuItem in menuFlyout.ItemsSource) 
      { 
       menuFlyout.Items.Add(new MenuFlyoutItem() 
       { 
        Text = menuItem.Text, 
        Command = menuItem.Command 
       }); 
      } 
     }); 
    } 
} 

public class ContextMenuCommand 
{ 
    public ContextMenuCommand(ICommand command, string text) 
    { 
     Command = command; 
     Text = text; 
    } 

    public string Text 
    { 
     get; private set; 
    } 

    public ICommand Command 
    { 
     get; private set; 
    } 
} 

Сниппает выше не слушает изменения ItemsSource, но вы можете легко адаптировать класс.

Смежные вопросы