How to make context menu work for windows phone?

前端 未结 2 1759
轮回少年
轮回少年 2020-12-06 23:12

I am using ContextMenu from Windows Phone Control toolkit. Wondering how do I know which list item in the list is pressed? It seems I can know which context menu is selected

相关标签:
2条回答
  • 2020-12-06 23:52

    The answer is: MVVM. Don't use the event registration in code-behind rather have a command be invoked in the ViewModel. First, Instead of binding to a Data object, bind to a ViewModel (or a ViewModel representing a single list item if you're in a list). Then instead of using the Click event, have your ViewModel expose a Command that can be invoke directly on the databound VM.

    Here's a simplified example from my United Nations News OSS WP7 app: (XAML, C#)

    <DataTemplate x:Key="ArticleItemDataTemplate">
        <StackPanel>
            <toolkit:ContextMenuService.ContextMenu>
                <toolkit:ContextMenu>
                    <toolkit:MenuItem Command="{Binding NavigateToArticle}" Header="read article"/>
                    <toolkit:MenuItem Command="{Binding ShareViaEmail}" Header="share via email"/>
                    <toolkit:MenuItem Command="{Binding ShareOnFacebook}" Header="share on facebook"/>
                    <toolkit:MenuItem Command="{Binding ShareOnTwitter}" Header="share on twitter"/>
                </toolkit:ContextMenu>
            </toolkit:ContextMenuService.ContextMenu>
            <TextBlockText="{Binding Title}">
        </StackPanel>
    </DataTemplate>
    
    public ICommand ShareOnTwitter
    {
        get
        {
            return new RelayCommand(() => 
                IoC.Get<ISocialShareService>().ShareOnTwitter(ShareableOnSocialNetwroks));
        }
    }
    
    public ICommand ShareOnFacebook
    {
        get
        {
            return new RelayCommand(() =>
                IoC.Get<ISocialShareService>().ShareOnFacebook(ShareableOnSocialNetwroks));
        }
    }
    
    public ICommand ShareViaEmail
    {
        get
        {
            return new RelayCommand(() =>
                IoC.Get<ISocialShareService>().ShareViaEmail(ShareableOnSocialNetwroks));
        }
    }
    

    And here's another simplified sample of that same idea used in my Neurons WP7 OSS project: (XAML, C#)

        <DataTemplate x:Key="YouTubeVideoItem">
            <Grid>
                <Button >
                    <toolkit:ContextMenuService.ContextMenu>
                        <toolkit:ContextMenu IsZoomEnabled="False">
                            <toolkit:MenuItem Command="{Binding NavigateToVideo}" Header="play video" />
                            <toolkit:MenuItem Command="{Binding ViewInBrowser}" Header="open in browser" />
                            <toolkit:MenuItem Command="{Binding SendInEmail}" Header="share via email" />
                            <toolkit:MenuItem Command="{Binding FacebookInBrowser}" Header="share on facebook" />
                            <toolkit:MenuItem Command="{Binding TweetInBrowser}" Header="share on twitter" />
                        </toolkit:ContextMenu>
                    </toolkit:ContextMenuService.ContextMenu>
                    <Custom:Interaction.Triggers>
                        <Custom:EventTrigger EventName="Click">
                            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding NavigateToVideo}"/>
                        </Custom:EventTrigger>
                    </Custom:Interaction.Triggers>
                    <StackPanel Orientation="Horizontal">
                        <Image Height="90" Source="{Binding ImageUrl}" />
                        <TextBlock Width="271" Text="{Binding Title}" />
                    </StackPanel>
                </Button>
            </Grid>
        </DataTemplate>
    
        public ICommand ViewInBrowser
        {
            get
            {
                return new RelayCommand(() =>
                    TaskInvoker.OpenWebBrowser(this.ExternalLink.OriginalString)
                );
            }
        }
    
        public ICommand TweetInBrowser
        {
            get
            {
                return new RelayCommand(() =>
                    IoC.Get<IMessenger>().Send(new NavigateToMessage(PageSources.WebBrowser, TwitterUri)));
            }
        }
    
        public ICommand FacebookInBrowser
        {
            get
            {
                return new RelayCommand(() =>
                    IoC.Get<IMessenger>().Send(new NavigateToMessage(PageSources.WebBrowser, FacebookUri)));
            }
        }
    
    0 讨论(0)
  • 2020-12-06 23:56

    I would also recommend MVVM, but it can be simplified. No need to go to the extreme of having a ViewModel for every object. The key is to bind the command to the DataContext of your ItemsControl (eg ListBox).

    Let's assume that your ItemTemplate is for a ListBox, the ListBox has it's ItemsSource property bound to your ViewModel. Your xaml would look like this:

    <ListBox x:Name="SongsListBox" ItemsSource="{Binding Songs}">
        <ListBox.ItemTemplate>
            <DataTemplate >
                <StackPanel >
                    <TextBlock Text="{Binding SName}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" />
                    <toolkit:ContextMenuService.ContextMenu>
                       <toolkit:ContextMenu>
                           <toolkit:MenuItem Header="Add to playlist" Command="{Binding DataContext.AddToPlaylistCommand, ElementName=SongsListBox}" CommandParameter="{Binding}"/>
                       </toolkit:ContextMenu>
                    </toolkit:ContextMenuService.ContextMenu>
                </StackPanel>              
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    Your ViewModel, would then have the property Songs, that is a collection of your model object. It also has an ICommand AddToPlaylistCommand. As I've said before, my favorite implementation of ICommand is the DelegateCommand from the PNP team.

    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel()
        {
            Songs = new ObservableCollection<Songs>();
            AddToPlaylistCommand = new DelegateCommand<Song>(AddToPlaylist);
        }
        public ICollection<Songs> Songs { get; set; }
        public ICommand AddToPlaylistCommand  { get; private set; }
    
        private void AddToPlaylist(Song song)
        {
            // I have full access to my model!
            // add the item to the playlist
        }
    
        // Other stuff for INotifyPropertyChanged
    }
    
    0 讨论(0)
提交回复
热议问题