C# 上下文菜单使用Mvvm不断获取错误对象

C# 上下文菜单使用Mvvm不断获取错误对象,c#,mvvm,windows-phone-8,windows-phone-toolkit,C#,Mvvm,Windows Phone 8,Windows Phone Toolkit,我正在制作一个winodws 8电话应用程序,并试图从Windows phone工具包中获得一个上下文菜单 我一直在遵循这一点,但我使用的不是列表框,而是WP8中内置的长列表选择器 <DataTemplate x:Key="GroceryListItemTemplate"> <StackPanel Grid.Column="1" Grid.Row="1"> <TextBlock x:Name="tbName" TextWrapping="Wr

我正在制作一个winodws 8电话应用程序,并试图从Windows phone工具包中获得一个上下文菜单

我一直在遵循这一点,但我使用的不是列表框,而是WP8中内置的长列表选择器

<DataTemplate x:Key="GroceryListItemTemplate">
    <StackPanel Grid.Column="1" Grid.Row="1">
        <TextBlock x:Name="tbName" TextWrapping="Wrap" Text="{Binding Name}" FontSize="32"/>
        <TextBlock x:Name="tbProductInfo" TextWrapping="Wrap" Text="{Binding ProductInfoLabel}" HorizontalAlignment="Left"/>
    </StackPanel>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu>
            <toolkit:MenuItem Header="Edit" 
                    Command="{Binding GroceryItemsVm.EditGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
            <toolkit:MenuItem Header="Delete" Command="{Binding GroceryItemsVm.DeleteGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</DataTemplate>

根据这些注释,您有一个
GroceryItemsVm
类,看起来像下面这样

public class GroceryItemVm : INotifyPropertyChanged
{
    public string Name { get; set; }
    public string ProductInfoLabel{ get; set; }

    public ICommand EditGroceryItemCmd { get; private set; }
    public ICommand DeleteGroceryItemCmd { get; private set; }
}
因此,LLS绑定到的
GroceryItems
属性将是

public IEnumerable<GroceryItemVm> GroceryItems { get; set;}

这是ContextMenu的常见问题。一段时间以来,我一直在想一个解决方案,四处寻找一些东西。你说你点击后,它永远不会正确

请尝试以下操作:

将卸载的处理程序添加到
contextmenu
中,如下所示:

<DataTemplate x:Key="GroceryListItemTemplate">
    <StackPanel Grid.Column="1" Grid.Row="1">
        <TextBlock x:Name="tbName" TextWrapping="Wrap" Text="{Binding Name}" FontSize="32"/>
        <TextBlock x:Name="tbProductInfo" TextWrapping="Wrap" Text="{Binding ProductInfoLabel}" HorizontalAlignment="Left"/>
    </StackPanel>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu ***Unloaded="ContextMenu_Unloaded"***>
            <toolkit:MenuItem Header="Edit" 
                    Command="{Binding GroceryItemsVm.EditGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
            <toolkit:MenuItem Header="Delete" Command="{Binding GroceryItemsVm.DeleteGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</DataTemplate>

让我知道这是否有效。

GroceryItemsVm.EditGroceryItemCmd?为什么命令不在GroceryItemViewModel的根目录中?如果这样做,就不需要使用长路径,只需使用{Binding Edit}。如果它位于根目录下,它如何知道需要将哪个杂货项目发送到视图模型?长列表选择器中的每个杂货项目本质上都需要它自己的上下文菜单,以便它知道正在编辑哪一行。您的上下文菜单绑定到属性
GroceryItemsVm
。这房子住在哪里?请记住,命令的绑定与常规绑定没有什么不同。如果
EditGroceryItemCmd
Name
ProductInfoLabel
位于同一个类中,则需要删除命令bindingGroceryItemsVm的前缀GroceryItemsVm is my View Model,其中包含EditGroceryItemCmd,Name和ProductInfoLabel属于一个模型类,并且直接来自该模型类。正如我所提到的,从命令绑定中删除该前缀。ContextMenu(和MenuItem)的DataContext与DataTemplate的其余部分(作为GroceryItemsVm的实例)相同。因此,您将直接将命令绑定到
EditGroceryItemCmd
DeleteGroceryItemCmd
。这也意味着从绑定中删除源代码。我回家后会发布我拥有的类,但你拥有的不是我拥有的。我只有一个关于GroceryItemVm类(视图模型)的。IEnumberable是GroceryItem的ObservableCollection,其属性为Name和ProductInfo。GroceryItemVm中只有一个EditGroceryItemCmd和DeleteGroceryItemCmd实例。明白了。一种选择是不将DataTemplate放在资源中,而是直接放在LLS下,并将命令绑定为my。如果不是,那么“定位器”在哪里定义?模板有权访问的是静态资源吗?该对象是否具有与LLS绑定到的实例相同的GroceryItemsVm实例?定位器是使用定位器模式的静态资源,MVVM light toolkit就是这样设置的。它将生成一个且仅一个GroceryItemsVm,并通过应用程序使用它。嗯,我尝试使用数据上下文,但与您的答案类似,但我遇到了相同的问题。我想我知道是什么问题,但不知道为什么。在我的编辑方法中,我导航到一个新页面,当我返回时,它就坏了。如果我不导航,一切都很好。初始测试看起来不错!在我说这是解决方案之前,我必须对它进行更多的测试。你知道为什么会这样吗?我在某处发现的。。。不确定为什么必须以这种方式使这些字段无效,但这与绑定有关。
public class GroceryItemVm : INotifyPropertyChanged
{
    public string Name { get; set; }
    public string ProductInfoLabel{ get; set; }

    public ICommand EditGroceryItemCmd { get; private set; }
    public ICommand DeleteGroceryItemCmd { get; private set; }
}
public IEnumerable<GroceryItemVm> GroceryItems { get; set;}
<DataTemplate x:Key="GroceryListItemTemplate">
    <StackPanel Grid.Column="1" Grid.Row="1">
        <TextBlock x:Name="tbName" TextWrapping="Wrap" Text="{Binding Name}" FontSize="32"/>
        <TextBlock x:Name="tbProductInfo" TextWrapping="Wrap" Text="{Binding ProductInfoLabel}" HorizontalAlignment="Left"/>
    </StackPanel>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu>
            <toolkit:MenuItem Header="Edit" Command="{Binding EditGroceryItemCmd}"/>
            <toolkit:MenuItem Header="Delete" Command="{Binding DeleteGroceryItemCmd}"/>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</DataTemplate>
<DataTemplate x:Key="GroceryListItemTemplate">
    <StackPanel Grid.Column="1" Grid.Row="1">
        <TextBlock x:Name="tbName" TextWrapping="Wrap" Text="{Binding Name}" FontSize="32"/>
        <TextBlock x:Name="tbProductInfo" TextWrapping="Wrap" Text="{Binding ProductInfoLabel}" HorizontalAlignment="Left"/>
    </StackPanel>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu ***Unloaded="ContextMenu_Unloaded"***>
            <toolkit:MenuItem Header="Edit" 
                    Command="{Binding GroceryItemsVm.EditGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
            <toolkit:MenuItem Header="Delete" Command="{Binding GroceryItemsVm.DeleteGroceryItemCmd, Source={StaticResource Locator}}"
                    CommandParameter="{Binding}"/>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</DataTemplate>
private void ContextMenu_Unloaded(object sender, RoutedEventArgs e)
{
    var conmen = (sender as ContextMenu);
    if (conmen != null)
        conmen.ClearValue(DataContextProperty);
}