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 but I have no way to know which list item is operated on. Please help. Thanks!
<DataTemplate x:Key="ListItemTemplate"> <StackPanel Grid.Column="1" VerticalAlignment="Top"> <TextBlock Tag="{Binding Index}" Text="{Binding SName}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" /> <toolkit:ContextMenuService.ContextMenu> <toolkit:ContextMenu> <toolkit:MenuItem Header="Add to playlist" Click="Move_Click"/> </toolkit:ContextMenu> </toolkit:ContextMenuService.ContextMenu> </StackPanel> private void Move_Click(object sender, RoutedEventArgs e) { String name = (string)((MenuItem)sender).Header; // how to know which index of the item is targeted on }
Answer: 1
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))); } }
by : JustinAngelhttp://stackoverflow.com/users/81687Answer: 2
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> Items { 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 }
by : Shawn Kendrothttp://stackoverflow.com/users/1054961
No comments:
Post a Comment
Send us your comment related to the topic mentioned on the blog