2013-05-29 93 views
16

我有一個WPF的DataGrid獲取WPF數據網格上下文菜單中單擊行

<DataGrid AutoGenerateColumns="False" Name="dataGrid1" IsReadOnly="True" > 
<DataGrid.Columns> 
    <DataGridTextColumn Header="Site" Binding="{Binding Site}" Width="150" /> 
    <DataGridTextColumn Header="Subject" Binding="{Binding Subject}" Width="310" /> 
</DataGrid.Columns> 
<DataGrid.ContextMenu> 
    <ContextMenu> 
     <MenuItem Header="Delete" Click="Context_Delete"> 
      <MenuItem.Icon> 
       <Image Width="12" Height="12" Source="Images/Delete.png" /> 
      </MenuItem.Icon> 
     </MenuItem> 
    </ContextMenu> 
</DataGrid.ContextMenu> 
</DataGrid> 

我有Click事件處理程序爲:

private void Context_Delete(object sender, System.EventArgs e) { } 

我如何獲得其上下文菜單是行點擊之前? sender對象是System.Windows.Controls.MenuItem,而不是DataGridRow。如何獲得點擊上下文菜單的DataGridRow(我在後面的代碼中設置了DataGrid.ItemSource

回答

26

因此,根據您的示例代碼,我假定您將DataGrid綁定到ObservableCollection的對象,您將屬性Site和Subject綁定到DataGridColumns。

本質上,你需要做的是找出綁定到被點擊的DataGridRow的項目,並從ObservableCollection中移除它。下面是一些示例代碼,您開始:

private void Context_Delete(object sender, RoutedEventArgs e) 
{ 
    //Get the clicked MenuItem 
    var menuItem = (MenuItem)sender; 

    //Get the ContextMenu to which the menuItem belongs 
    var contextMenu = (ContextMenu)menuItem.Parent; 

    //Find the placementTarget 
    var item = (DataGrid)contextMenu.PlacementTarget; 

    //Get the underlying item, that you cast to your object that is bound 
    //to the DataGrid (and has subject and state as property) 
    var toDeleteFromBindedList = (YourObject)item.SelectedCells[0].Item; 

    //Remove the toDeleteFromBindedList object from your ObservableCollection 
    yourObservableCollection.Remove(toDeleteFromBindedList); 
} 
+0

謝謝StevenHouben這工作完美! –

+0

這讓我從嚴重的頭髮拉動時刻中解脫出來。它完美的作品。 – coffeecoder

6

通常情況下,你不處理行(如果你這樣做 - 再想一想原因) - 而是使用視圖模型。當你打開上下文菜單時,你可以選擇你的項目,因此可以通過DataGrid.SelectedItem屬性訪問它。但是,如果你真的需要DataGridRow - 你有你的DataGrid.SelectedIndex,並且在這裏有很多關於如何獲得該行的答案。像Get row in datagrid

+0

謝謝morincer。我對WPF沒有太多的知識,一旦我獲得了時間,就需要閱讀它。 –

0

爲了用一個例子擴大上述morincer的角度來看,我結束了一個更簡單的方法...

private void MenuItem_OnClickRemoveSource(object sender, RoutedEventArgs e) 
{ 
    if (SourceDataGrid.SelectedItem == null) return; //safety first 

    _importViewModel.SourceList.Remove((SourceFileInfo)SourceDataGrid.SelectedItem); 
} 

在我的情況下,

_importViewModel.SourceList 

是行被綁定到的ObservableCollection。因此,根據最佳做法,我簡單地從集合中移除選定的項目,並且綁定負責處理UI。

1

dsfgsho的答案爲我工作,但右擊網格行不會自動選擇它。這意味着如果您的焦點位於其他地方,並且您右鍵單擊並選擇一個上下文菜單項,則您可以在item.SelectedCells [0]上獲得超出範圍的異常,或者如果選擇了一行並右鍵單擊其他項行,你可能會得到意想不到的結果。

我通過處理Datagrid上的「PreviewMouseRightButtonDown」來處理這個問題。在這裏,我明確地選擇一個行,當它右鍵單擊。我忘記了我的UIHelpers類來自哪裏(可能在本站的其他地方 - 我正在使用它來解決拖動&拖放項目),但如果您遇到此問題,這應該指向正確的方向。這是公認的答案的擴展:

// handle right mouse click to select the correct item for context menu usage 
    private void myDataGrid_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     //find the clicked row 
     DataGridRow row = UIHelpers.TryFindFromPoint<DataGridRow>((UIElement) sender, e.GetPosition(myDataGrid)); 
     if (row == null) 
     { 
      Debug.WriteLine("Row is null"); 
      return; 
     } 
     else 
     { 
      Debug.WriteLine("Grid Row Index is " + row.GetIndex().ToString()); 
      (sender as DataGrid).SelectedIndex = row.GetIndex(); 
     } 
    }