Search code examples
c#xamlmvvmwindows-store-appsprism

menuflyout choosed item passing to command mvvm


I'm trying to bind menuflyoutitem of choosen item in listview to Delete Command. Flyoutmenu shows when I'm holding element on list, so I can't bind it to SelectedItem property in viewmodel.

SelectedItem property works fine, but i have to tap element first and then hold item for showing menu and then delete. How can i pass sender from Holding to my property in viewmodel?

View:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Row="0"
               Text="My List App"
               HorizontalAlignment="Center"
               Style="{ThemeResource HeaderTextBlockStyle}" />
    <ListView x:Name="myListView"
              Grid.Row="1"
              ItemsSource="{Binding AllMyLists}"
              SelectedItem="{Binding SelectedList, Mode=TwoWay}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <i:Interaction.Behaviors>
                        <core:EventTriggerBehavior EventName="Holding">
                            <controls:OpenMenuFlyoutAction />
                        </core:EventTriggerBehavior>
                    </i:Interaction.Behaviors>
                    <FlyoutBase.AttachedFlyout>
                        <MenuFlyout>
                            <MenuFlyoutItem Text="Delete"
                                            Command="{Binding ElementName=myListView, Path=DataContext.DeleteEntryListCommand}" />
                        </MenuFlyout>
                    </FlyoutBase.AttachedFlyout>
                    <TextBlock Text="{Binding Name}"
                               Style="{ThemeResource ListViewItemTextBlockStyle}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

OpenMenuFlyoutAction for used for showing flyoutMenu:

public class OpenMenuFlyoutAction : DependencyObject, IAction
{
    public object Execute(object sender, object parameter)
    {
        FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender);
        return sender;
    }
}

And My ViewModel:

public class AllListsPageViewModel : Microsoft.Practices.Prism.Mvvm.ViewModel, Interfaces.IAllListsPageViewModel
{
    #region Fields

    private ObservableCollection<EntryList> _allMyLists;
    private EntryList _selectedList;

    private DelegateCommand _addEntryListCommand;
    private DelegateCommand _deleteEntryListCommand;

    private readonly INavigationService _navigationService;
    #endregion //Fields

    #region Construction

    public AllListsPageViewModel(INavigationService navigationService) { ... }
    #endregion //Construction

    #region Properties

    public ObservableCollection<EntryList> AllMyLists
    {
        get { return _allMyLists; }
        set { SetProperty(ref _allMyLists, value); }
    }

    public EntryList SelectedList
    {
        get { return _selectedList; }
        set { SetProperty(ref _selectedList, value); }
    }
    #endregion //Properties

    #region Methods

    private void loadData() { }

    private bool _canAddEntryList() { return true; }

    private void _addEntryList() { ... }

    private bool _canDeleteEntryList() { ... }

    private void _deleteEntryList()
    {
        //How to get sender from holding event here?
        _allMyLists.Remove(_selectedList);
    }
    #endregion //Methods

    #region Commands

    public ICommand AddEntryListCommand { ... }

    public ICommand DeleteEntryListCommand
    {
        get
        {
            if (_deleteEntryListCommand == null)
            {
                _deleteEntryListCommand = new DelegateCommand(_deleteEntryList, _canDeleteEntryList);
            }
            return _deleteEntryListCommand;
        }
    }
    #endregion //Commands
}

Thanks in advance.


Solution

  • I had the same problem today and I have resolved as follows:

    namespace your.namespace
    {
        using Microsoft.Xaml.Interactivity;
        using Windows.UI.Xaml;
        using Windows.UI.Xaml.Controls.Primitives;
        using Windows.UI.Xaml.Input;
    
        public class OpenMenuFlyoutAction : DependencyObject, IAction
        {
            private static object holdedObject;
    
            public object Execute(object sender, object parameter)
            {
                FrameworkElement senderElement = sender as FrameworkElement;
                FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);
                flyoutBase.ShowAt(senderElement);
    
                var eventArgs = parameter as HoldingRoutedEventArgs;
                if (eventArgs == null)
                {
                    return null;
                }
    
                var element = eventArgs.OriginalSource as FrameworkElement;
                if (element != null)
                {
                    HoldedObject = element.DataContext;
                }
    
                return null;
            }
    
            public static object HoldedObject
            {
                get { return holdedObject; }
                set
                {
                    holdedObject = value;
                }
            }
        }
    }
    

    Then you can access the object as follows:

    var foo = OpenMenuFlyoutAction.HoldedObject as Foo;
    

    I think it's not bad solution that the HoldedObject is static as you can not do hold two items at the same time.