Silverlight 如何使上下文菜单适用于windows phone?

Silverlight 如何使上下文菜单适用于windows phone?,silverlight,xaml,contextmenu,windows-phone-8,silverlight-toolkit,Silverlight,Xaml,Contextmenu,Windows Phone 8,Silverlight Toolkit,我正在使用Windows Phone控件工具包中的ContextMenu。想知道我如何知道列表中的哪个列表项被按下?似乎我可以知道选择了哪一个上下文菜单,但我无法知道操作的是哪一个列表项。请帮忙。谢谢 <DataTemplate x:Key="ListItemTemplate"> <StackPanel Grid.Column="1" VerticalAlignment="Top"> <Text

我正在使用Windows Phone控件工具包中的ContextMenu。想知道我如何知道列表中的哪个列表项被按下?似乎我可以知道选择了哪一个上下文菜单,但我无法知道操作的是哪一个列表项。请帮忙。谢谢

        <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
    }

私有无效移动\单击(对象发送者,路由目标)
{
字符串名称=(字符串)((MenuItem)sender).Header;
//如何知道项目的哪个索引是针对的
}

答案是:MVVM。不要在代码隐藏中使用事件注册,而是在ViewModel中调用命令。首先,不要绑定到数据对象,而是绑定到ViewModel(如果您在列表中,则绑定到表示单个列表项的ViewModel)。然后,不要使用Click事件,而是让ViewModel公开一个可以直接在数据绑定VM上调用的命令

下面是我的OSS WP7应用程序中的一个简化示例:(,)


公共ICommand ShareOnTwitter
{
得到
{
返回新的RelayCommand(()=>
IoC.Get().ShareOnTwitter(ShareableOnSocialNetwroks));
}
}
公共ICommand共享Facebook
{
得到
{
返回新的RelayCommand(()=>
IoC.Get().ShareOnFacebook(ShareableOnSocialNetwroks));
}
}
公共ICommand共享电子邮件
{
得到
{
返回新的RelayCommand(()=>
IoC.Get().ShareViaEmail(ShareableOnSocialNetwroks));
}
}
下面是我的WP7OSS项目中使用的相同想法的另一个简化示例:(,)


public图标命令和视图浏览器
{
得到
{
返回新的RelayCommand(()=>
TaskInvoker.OpenWebBrowser(this.ExternalLink.OriginalString)
);
}
}
公共i命令和TweetInBrowser
{
得到
{
返回新的RelayCommand(()=>
IoC.Get().Send(新的NavigateToMessage(PageSources.WebBrowser,TwitterUri));
}
}
公共ICommand FacebookInBrowser
{
得到
{
返回新的RelayCommand(()=>
IoC.Get().Send(新的NavigateToMessage(PageSources.WebBrowser,FacebookUri));
}
}

我也推荐MVVM,但它可以简化。无需极端地为每个对象创建ViewModel。关键是将命令绑定到ItemsControl(例如ListBox)的DataContext

假设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>

唯一的问题是,
Title
像是绑定的多个项中的一个的属性,而命令绑定通常位于父视图模型上。对于您选择的模型,命令基本上会被重新定义好几次。这不是问题,这是一个特性。这实际上是我使用的代码示例。与数据绑定到数据对象(例如Cow)不同,您应该将该对象包装到项目视图模型(例如CowViewModel)中,并将ItemsControl.ItemSource数据绑定到列表而不是列表。然后,CowViewModel可以公开您想要的任何命令(例如CowViewModel.cowCommand)。如果您有一个DataGrid,在一个DataRow中有两个按钮,那么这是相同的解决方案。看看我提供的示例。嗯,这是一种明显的代码味道,所以我个人不建议这样做。(另外,你的IoC对象是一个服务定位器,它与控制反转无关,但这是一个不同的讨论。)我不同意它是一种代码气味。当有一个项目列表并且每个项目可以执行2个或更多操作时,这是唯一合理的解决方案。赋予PageViewModel明确不属于它的职责(可能与其他PageViewModels共享)是一个代码。想想一个DataGrid示例,每个DataRow中有列表和两个按钮。感谢你们提供了有价值的答案!在阅读了你的建议后,我已经开始工作了。谢谢!这对我帮助很大!我可以根据自己的需要复制粘贴。这是吹毛求疵,但你应该将歌曲的setter设置为私有。我不同意,有些情况下,你可能想从其他地方设置此设置。我使用的是MVVM light,因此我的代码有点不同,但这对我不适用
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
}