上下文菜单使用Mvvm继续获取错误的对象

时间:2014-03-19 14:43:19

标签: c# mvvm windows-phone-8 windows-phone-toolkit

我正在制作一个winodws 8手机应用程序,并尝试从Windows Phone工具包中获取上下文菜单。

我一直关注这个tutorial但是我没有使用列表框而是使用内置于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>

以上是我的代码看起来像

的细节

这是我的列表选择器

<phone:LongListSelector IsGroupingEnabled="True" ItemsSource="{Binding GroceryItems}"    HideEmptyGroups="True" LayoutMode="List" Grid.Row="1">     
            <phone:LongListSelector.ItemTemplate>
                <StaticResource ResourceKey="GroceryListItemTemplate"/>
            </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

这是我的mvvm代码

public class GroceryItemsVm : ViewModelBase
{

    public GroceryItemsVm()
    {


        if (IsInDesignMode)
        {


        }
        else
        {

            EditGroceryItemCmd = new RelayCommand<GroceryItem>(this.Edit);
            DeleteGroceryItemCmd = new RelayCommand<GroceryItem>(this.Delete);

            GroceryItems = // method that gets all items back as grouped.



        }
    }

      private List<Group<GroceryItem>> groceryItems = null;

            /// <summary>
            /// Sets and gets the GroceryItems property.
            /// Changes to that property's value raise the PropertyChanged event. 
            /// </summary>
            public List<Group<GroceryItem>> GroceryItems
            {
                get
                {
                    return groceryItems;
                }

                set
                {
                    if (groceryItems == value)
                    {
                        return;
                    }

                    RaisePropertyChanging(() => GroceryItems);
                    groceryItems = value;
                    RaisePropertyChanged(() => GroceryItems);
                }
            }




    private async void Delete(GroceryItem obj)
    {
       // trigged on context delete
    }

    private void Edit(GroceryItem obj)
    {
        // triggered on context edit
    }



    public RelayCommand<GroceryItem> EditGroceryItemCmd
    {
        get;
        private set;
    }

    public RelayCommand<GroceryItem> DeleteGroceryItemCmd
    {
        get;
        private set;
    }

}


    public class GroceryItem : ObservableObject
        {
            /// <summary>
            /// The <see cref="Name" /> property's name.
            /// </summary>
            public const string NamePropertyName = "Name";

            private string name = "";

            /// <summary>
            /// Sets and gets the Name property.
            /// Changes to that property's value raise the PropertyChanged event. 
            /// </summary>
            public string Name
            {
                get
                {
                    return name;
                }

                set
                {
                    if (name == value)
                    {
                        return;
                    }

                    RaisePropertyChanging(() => Name);
                    name = value;
                    RaisePropertyChanged(() => Name);
                }
            }
        }

现在,当我运行它时,它第一次起作用,无论我选择编辑它的任何项目,都会为它获得正确的对象。但是,下一个对象将始终相同。选择完成后,它永远不会改变它的选择。

修改

这是一个例子。

https://onedrive.live.com/redir?resid=FAE864D71B4770C6!19080&authkey=!ACUC2xXmZLVD7fE&ithint=file%2c.zip

  1. 运行它
  2. 触发上下文菜单以显示&#34; 1&#34;
  3. 点击编辑 - 注释对话框消息(将说1)
  4. 点击&#34;返回按钮&#34;
  5. 触发上下文菜单以显示&#34; 3&#34;
  6. 点击编辑 - 注释对话框消息(将说3)
  7. 我唯一能想到的是覆盖我要访问的页面的后退按钮,然后只需执行导航到页面。这有点愚蠢,但这是我能想到的全部。

      public partial class MvvmView1 : PhoneApplicationPage
        {
            // Constructor
            public MvvmView1()
            {
                InitializeComponent();
    
                // Sample code to localize the ApplicationBar
                //BuildLocalizedApplicationBar();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                NavigationService.GoBack();
            }
    
    
            protected override void OnBackKeyPress(CancelEventArgs e)
            {
                NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
            }
    
    
        }
    

2 个答案:

答案 0 :(得分:1)

根据评论,您有一个类似于以下内容的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;}

如果是这种情况,那么DataTemplate中项目的DataContext就是GroceryItemsVm的实例。 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>
            <toolkit:MenuItem Header="Edit" Command="{Binding EditGroceryItemCmd}"/>
            <toolkit:MenuItem Header="Delete" Command="{Binding DeleteGroceryItemCmd}"/>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</DataTemplate>

答案 1 :(得分:1)

这是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>

删除 * 我添加了它们以强调更改。 然后该处理程序的代码将是:

private void ContextMenu_Unloaded(object sender, RoutedEventArgs e)
{
    var conmen = (sender as ContextMenu);
    if (conmen != null)
        conmen.ClearValue(DataContextProperty);
}

让我知道这是否有效。