2014-03-19 17 views
1

我正在製作一個winodws 8手機應用程序,並嘗試從Windows Phone工具包獲取上下文菜單。上下文菜單使用Mvvm保持錯誤的對象

我一直在關注這個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. 觸發上下文菜單顯示在 「1」
  3. 命中編輯 - 注意對話消息(會說1)
  4. 命中 「返回鍵」
  5. 觸發上下文菜單以顯示「3」
  6. 點擊編輯 - 註釋對話框消息(將會顯示3)

我能想到的唯一的事情就是覆蓋我要去的頁面的後退按鈕,並且只需導航到頁面即可。這是有點愚蠢,但這是我能想到的。

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


    } 
+0

GroceryItemsVm.EditGroceryItemCmd?爲什麼不是GroceryItemViewModel的根目錄中的命令?如果你這樣做,你不需要使用長路徑,只需{綁定編輯}。 –

+0

它如何知道如果它位於根目錄下,它需要發送給視圖模型的是哪個Grocery Item?長列表選擇器中的每個Grocery Item實質上都需要它自己的上下文菜單,因此它知道正在編輯哪一行。 – chobo2

+1

您的ContextMenu綁定到屬性'GroceryItemsVm'。這個屬性在哪裏?請記住,命令的綁定與常規綁定沒有區別。如果'EditGroceryItemCmd'與'Name'和'ProductInfoLabel'存在於同一個類中,那麼您需要刪除用於命令綁定的'GroceryItemsVm'前綴 –

回答

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

讓我知道這是否正常工作。

+0

初始測試看起來不錯!在我可以說它是解決方案之前,我必須進行更多的測試。你知道這是爲什麼嗎? – chobo2

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

這樣一來,GroceryItems財產,你的LLS綁定到會

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> 
+0

我會在我回到家時發佈的課程,但你擁有的並不是我擁有的課程。我只有在GroceryItemVm類(視圖模型)。 IEnmberable是GroceryItem的ObservableCollection,它具有Name和ProductInfo的屬性。 GroceryItemVm中只有1個EditGroceryItemCmd和DeleteGroceryItemCmd實例。 – chobo2

+0

好吧,我更新了我的帖子。希望它現在更有意義。 – chobo2

+0

明白了。一種選擇是不將DataTemplate放在資源中,而是直接放在LLS下,並將命令綁​​定爲我的[其他答案](http://stackoverflow.com/a/14168934/1054961)。如果不是那樣,「Locator」在哪裏定義?它是模板有權訪問的靜態資源嗎?該對象是否有與LLS綁定的**實例相同的**實例的GroceryItemsVm? –

相關問題