Как заставить работать контекстное меню для Windows Phone?
Я использую ContextMenu из набора инструментов управления Windows Phone. Хотите знать, как узнать, какой элемент списка в списке нажата? Кажется, я могу знать, какое контекстное меню выбрано, но у меня нет возможности узнать, над каким элементом списка работает. Пожалуйста помоги. Спасибо!
<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
}
2 ответа
Я также рекомендовал бы MVVM, но это может быть упрощено. Нет необходимости доходить до крайности наличия ViewModel для каждого объекта. Ключ должен привязать команду к DataContext вашего ItemsControl (например, ListBox).
Давайте предположим, что ваш ItemTemplate предназначен для ListBox, у ListBox есть свойство ItemsSource, привязанное к вашей ViewModel. Ваш xaml будет выглядеть так:
<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>
Ваша ViewModel будет иметь свойство Songs
это коллекция вашего модельного объекта. У этого также есть ICommand AddToPlaylistCommand
, Как я уже говорил, моя любимая реализация ICommand - это DelegateCommand от команды PNP.
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
}
Ответ: MVVM. Не используйте регистрацию событий в выделенном фрагменте кода, а вызовите команду во ViewModel. Во-первых, вместо привязки к объекту данных, привязка к ViewModel (или ViewModel, представляющей один элемент списка, если вы находитесь в списке). Затем вместо использования события Click ваша ViewModel предоставляет команду, которую можно вызывать непосредственно на виртуальной машине с привязкой к базе данных.
Вот упрощенный пример из моего приложения United States News OSS WP7: ( 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));
}
}
А вот еще один упрощенный пример той же идеи, которая использовалась в моем проекте Nessons WP7 OSS: ( 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)));
}
}