Как заставить работать контекстное меню для 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)));
        }
    }
Другие вопросы по тегам