Get RowIndex via ContextMenu? - winforms

I'm trying to get a rowindex of row at which I right clicked to call a contextmenu.
DatagridView's property contextmenu is set to this contextmenu.
Is it possible in some simple way?
Best regards

Yes, you need to handle the MouseDown event for your DataGridView and then use the HitTest method to return row and/or column index for the given coordinates.
For example:
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
DataGridView.HitTestInfo hit = dataGridView1.HitTest(e.X, e.Y);
if (hit.Type == DataGridViewHitTestType.Cell)
{
Console.WriteLine(hit.RowIndex);
}
}
}

I change the selection in the CellContextMenuStripNeeded event and then use the SelectedRows member to find it.
private void dataGridView_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
{
var Dgv = sender as DataGridView;
if (Dgv != null)
{
// Change the selection to reflect the right-click
Dgv.ClearSelection();
Dgv.Rows[e.RowIndex].Selected = true;
}
}
private void myToolStripMenuItem_Click(object sender, EventArgs e)
{
// Now pick up the selection as we know this is the row we right-clicked on
if (dataGridView.SelectedRows.Count > 0)
{
DoSomethingAmazing(dataGridView.SelectedRows[0]);
}
}
This also has the desired effect of highlighting a row that you r-click on.

Related

How to enable editing for new inserted row in a GridView while gridview is allowedit = false?

I have a GridView control of xtraGrid suite in a form.
When I open the form for first time it is AllowEdit = false. I want that when I press on add new row link(built in by control) to make editable this only new inserted row. I read that I should use ShowingEditor event but I don't know how.
I wrote this so far but this does not editable the row:
private void gridViewNote_ShowingEditor(object sender, System.ComponentModel.CancelEventArgs e)
{
//this is first tryout
//if (gridViewNote.IsNewItemRow(gridViewNote.FocusedRowHandle))// == gridViewNote.GetFocusedDataRow())
//{
// gridColumnStagione.OptionsColumn.AllowEdit = true;
//}
//second tryout
GridView view = sender as GridView;
SchedeMaterialiDaTaglioDS.SMTAGL_NOTERow currentRow = gridViewNote.GetFocusedDataRow() as SchedeMaterialiDaTaglioDS.SMTAGL_NOTERow;
SchedeMaterialiDaTaglioDS.SMTAGL_NOTEDataTable changesTable = dsSchMatTaglio.SMTAGL_NOTE.GetChanges() as SchedeMaterialiDaTaglioDS.SMTAGL_NOTEDataTable;
e.Cancel = !view.IsNewItemRow(view.FocusedRowHandle) &&
!changesTable.Contains(currentRow);// set.Inserts.Contains(order);
}
I hope I understood your question. A few simple ways of doing this:
Adding a repository item to each column and handle the ShowingEditor event, using e.Cancel if this is supposed to be read only.
Popping up a window/textboxes, letting the user insert values and add the row with values already inserted via code.
assigning two different repository items to the same column using gridView.CustomRowCellEdit event. like such:
RepositoryItemTextEdit rep = new RepositoryItemTextEdit();
RepositoryItemTextEdit noRep = new RepositoryItemTextEdit();
noRep.ReadOnly = true;
private void button1_Click(object sender, EventArgs e)
{
gridView1.AddNewRow();
justAddedName = true;
gridView1.RefreshData();
}
private void gridView1_CustomRowCellEdit(object sender, DevExpress.XtraGrid.Views.Grid.CustomRowCellEditEventArgs e)
{
if (e.Column == colname)
{
if (e.RowHandle == gridView1.RowCount - 1 && justAddedName)
{
e.RepositoryItem = rep;
}
else
{
e.RepositoryItem = noRep;
}
}
}
It's not complete, just a direction to explore.
Hope I helped.

Check only one ToolStripMenuItem

I have a ToolStrip with multiple ToolStripDropDownButtons, each has a set of DropDownItems.
When the user clicks on an DropDownItem, the check mark is shown.
By default, multiple items can be clicked and therefore multiple check marks appear.
What I'm trying to do is when the user clicks one DropDownItem, the other already checked items should be unchecked. In other words, there should always be only one checked item in the DropDown list.
I've been dabbling with it for some time but I can't really figure out how to keep the current checked item as it is while uncheck other items.
Below is the code I have as of now.
private void subietm1ToolStripMenuItem_Click(object sender, EventArgs e)
{
UncheckOtherToolStripMenuItems(sender);
}
public void UncheckOtherToolStripMenuItems(object selectedMenuItem)
{
List<ToolStripDropDownButton> dropdownButtons = new List<ToolStripDropDownButton>();
foreach (ToolStripItem item in toolStrip1.Items)
{
if (item is ToolStripDropDownButton)
{
dropdownButtons.Add((ToolStripDropDownButton)item);
}
}
foreach (ToolStripDropDownButton btn in dropdownButtons)
{
foreach (ToolStripMenuItem d in btn.DropDownItems)
{
if (d.Checked)
d.CheckState = CheckState.Unchecked;
}
}
}
If someone could shed some light on this or tell me an easy way to go about it, I'd be grateful.
Thank you.
So easy...
Implement their method as described below:
private void subietm1ToolStripMenuItem_Click(object sender, EventArgs e)
{
UncheckOtherToolStripMenuItems((ToolStripMenuItem)sender);
}
public void UncheckOtherToolStripMenuItems(ToolStripMenuItem selectedMenuItem)
{
selectedMenuItem.Checked = true;
// Select the other MenuItens from the ParentMenu(OwnerItens) and unchecked this,
// The current Linq Expression verify if the item is a real ToolStripMenuItem
// and if the item is a another ToolStripMenuItem to uncheck this.
foreach (var ltoolStripMenuItem in (from object
item in selectedMenuItem.Owner.Items
let ltoolStripMenuItem = item as ToolStripMenuItem
where ltoolStripMenuItem != null
where !item.Equals(selectedMenuItem)
select ltoolStripMenuItem))
(ltoolStripMenuItem).Checked = false;
// This line is optional, for show the mainMenu after click
selectedMenuItem.Owner.Show();
}
One detail is that you can implement the same method for all click menuItens, for this add same call for method UncheckOtherToolStripMenuItems((ToolStripMenuItem)sender); into the Event click for each ToolstripMenuItem, see this example to the another two ToolstripMenuItens:
private void subietm2ToolStripMenuItem_Click(object sender, EventArgs e)
{
UncheckOtherToolStripMenuItems((ToolStripMenuItem)sender);
}
private void subietm3ToolStripMenuItem_Click(object sender, EventArgs e)
{
UncheckOtherToolStripMenuItems((ToolStripMenuItem)sender);
}
I just set all the items in my menu with the event of item_Click so if one is clicked then it will just run the code below. Dont need an event for each button that way.
private void item_Click(object sender, EventArgs e)
{
// Set the current clicked item to item
ToolStripMenuItem item = sender as ToolStripMenuItem;
// Loop through all items in the subMenu and uncheck them but do check the clicked item
foreach (ToolStripMenuItem tempItemp in (ToolStripMenuItem)item.OwnerItem.DropDownItems)
{
if (tempItemp == item)
tempItemp.Checked = true;
else
tempItemp.Checked = false;
}
}
If you want to add several items to your list during runtime and have them connected in the way above you can run the below code.
private void subItemsMenus(ToolStripMenuItem parentItem, string[] listItems)
{
// Clear tool strip items first
parentItem.DropDownItems.Clear();
// Add items that are in the list
foreach (string subMenuItem in listItems)
{
ToolStripMenuItem item = new ToolStripMenuItem();
//Name that will appear on the menu
item.Text = subMenuItem;
//Put in the Name property whatever necessary to retrieve your data on click event
item.Name = subMenuItem;
//On-Click event
item.Click += new EventHandler(item_Click);
//Add the submenu to the parent menu
parentItem.DropDownItems.Add(item);
}
I have another way which works:
Each item is going to ToolStripMenuItem_CheckStateChanged(object sender, EventArgs e)
and every item has its own tag 1, 2, 3, 4, 5.
One item is checked on start and has tag = 1.
int selecteditem = 1;
bool atwork = false;
private void dzienToolStripMenuItem_CheckStateChanged(object sender, EventArgs e)
{
if (atwork) return;
else atwork = true;
selecteditem = Convert.ToInt32(((ToolStripMenuItem)sender).Tag);
foreach (ToolStripMenuItem it in sometooltipdropdown.DropDownItems)
{
if (Convert.ToInt32(it.Tag) != selecteditem)
{
it.Checked = false;
}
}
atwork = false;
}
The easiest way is add DropDownItemClicked Event and create own method:
private void toolStripDropDownButton1_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if (e.ClickedItem != null)
{
CheckSelected((ToolStripDropDownButton)sender, e.ClickedItem);
}
}
private void CheckSelected(ToolStripDropDownButton button, ToolStripItem selectedItem)
{
foreach (ToolStripMenuItem item in button.DropDownItems)
{
item.Checked = (item.Name == selectedItem.Name) ? true : false;
}
}
You could get the count by copying to an array and then use extensions.
ToolStripItem[] controls = new ToolStripItem[ToolStrip.DropDownItems.Count];
ToolStrip.DropDownItems.CopyTo(controls,0);
intcheckCount = controls.Count(c => (c as ToolStripMenuItem).Checked);
if (checkCount == 0) // must keep 1 selection
item.Checked = true;
else if (checkCount > 1) //uncheck all others
controls.Cast<ToolStripMenuItem>().Where(c => c.Checked && c.Name != item.Name)
.ToList().ForEach(s => s.Checked = false);

Change GridRowStyle in Telerik WinForm

i have a field in my database for detect font syle of a row.
font syle is Regular where it is true.
I want to changing my row style when select it. i write this :
private void myGrid_SelectionChanged(object sender, EventArgs e)
{
DataBaseComponent.EditFieldofObject(object1.Serial, true);
if (myGrid.SelectedRows[0].VisualElement != null)
myGrid.SelectedRows[0].VisualElement.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(178)));
myGrid.SelectedRows[0].Cells["myField"].Value = true;
}
but it doesnot work and i must bind grid again to see this change.
Why not use ItemDataBound instead of SelectionChanged? This will work for your needs.
protected void myGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item is GridDataItem)
{
GridDataItem dataBoundItem = (GridDataItem)e.Item;
if (dataBoundItem["ColumnName"].Text.ToString() == "True")
{
// Do something here
}
}
}
There is a good article on Telerik explaining it.

In Silverlight Datagrid, How to add a new row when focus goes away from Last Row?

I want to add a new row in my Silverlight DataGrid, when user try to go from LastRow to NextRow by Tab/Enter (as it last row, DataGrid loses focus). I can not use RowEditEnded event as it will fire even if i move to a PreviousRow from LastRow.
Can anyone help me achieve this?
If you look at DataGrid source code you can see that it traps key down event (f.i. to realize functionality like go to next row on enter pressed). As solution I propose to implement own grid inherited from DataGrid and add event which raised when user presses enter(or other) button. Own control:
public class MyDataGrid : DataGrid
{
public event EventHandler OnLastRowEnterPressed;
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (ItemsSource != null
&& ItemsSource.Cast<object>().Count() - 1 == SelectedIndex
&& e.Key == Key.Enter)
{
RaiseLastRowEnterPressed();
}
}
private void RaiseLastRowEnterPressed()
{
if (OnLastRowEnterPressed != null)
OnLastRowEnterPressed(this, EventArgs.Empty);
}
}
Using:
ObservableCollection<Foo> source = new ObservableCollection<Foo>()
{
new Foo(), new Foo(), new Foo(),
};
myDataGrid.OnLastRowEnterPressed += (s, e) => source.Add(new Foo());
myDataGrid.ItemsSource = source;
well vladimir, there seems to be no simple/direct way to add new row after last row exit. your solution will work but with consequences of event being raised in other key press events also. i have come up with the combination of events to get the solution.
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
addFlag = (e.Key == Key.Tab);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
addFlag = (addFlag && true);
base.OnLostFocus(e);
}
protected override void OnRowEditEnded(DataGridRowEditEndedEventArgs e)
{
base.OnRowEditEnded(e);
addFlag = (addFlag && IsLastRowSelected);
if (addFlag)
AddItem();
addFlag = false;
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
addFlag = false;
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
addFlag = false;
}
private void AddItem()
{
if (RaiseAddEvent!= null)
{
this.Focus();
RaiseAddEvent(this, EventArgs.Empty);
this.UpdateLayout();
this.CurrentColumn = this.Columns[0];
this.BeginEdit();
}
}
You can use Routed events concept where trapping the Enter/Tab key , you can add new row to the data grid control.
I will expose by few steps. So lets start now..
1)Declare your event in constructor of this class.
this.DataGrid1.KeyDown += new KeyEventHandler(DataGrid1_KeyDown);
you also can it in XAML file.
...KeyDown="DataGrid1_KeyDown".....
2) Go to your keydown event & wrie the code.
var focusedElement = FocusManager.GetFocusedElement();
DataGrid detailsDataGrid = sender as DataGrid;
int dataGridrows = detailsDataGrid.ItemsSource.OfType<object>().Count();
if (e.Key == Key.Tab && (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
return;
if (e.Key == Key.Tab)
try
{
detailsDataGrid.SelectedIndex = row.GetIndex();
{
itemMaster.TransactionChilds.Add(transactionChild);
detailsDataGrid.SelectedItem = transactionChild;
}
}
3) Now code line by line..
DataGridRow row = DataGridRow.GetRowContainingElement(focusedElement as FrameworkElement);
DataGridColumn column = DataGridColumn.GetColumnContainingElement(focusedElement as FrameworkElement);
TransactionMaster itemMaster = this.DataFormVoucher.CurrentItem as TransactionMaster;
decimal serialNumber = 0;
if (buttonPress == "Modify")
if (dataGridrows - 1 == detailsDataGrid.SelectedIndex && column.DisplayIndex == 5)
TransactionChild transactionChild = new TransactionChild()"[None]",DateTime.Now.Date,catch (Exception ex)Console.WriteLine(ex.Message);
.DataGridChild.KeyDown += new KeyEventHandler(DataGridChild_KeyDown);
3) Now understand the code line by line
i) first 3 lines are used to take which row of a datagrid is selected.
ii)When new row will add in this case i have used Tab key you can also change this.Another things is if an user predd Tab+Shift then it will go through (default as control focus).
iii) then check is it last row & last column of this grid, if yes then add new row or else.
iv) to add a blank new row just pass your object (EDMX Model Table)

What is the "pressed the delete key" event for the WPF Datagrid?

I want to enable the user to highlight a row on the WPF DataGrid and press delete key to delete the row.
the functionality is already built into the UI of the grid, so to the user, the row disappears
I currently handle this on the SelectionChanged event (code below)
I loop through all the "e.RemovedItems" and delete them with LINQ
Problem is: even when you simply select a row and move off of it, selection change is fired and that row is in e.RemovedItems (which is odd, why would simply selecting something put it in a RemovedItems container?).
So I am looking for a DeleteKeyPressed event so I can simply handle it. What is that event called?
I am using the March 2009 toolkit.
XAML:
<Grid DockPanel.Dock="Bottom">
<toolkit:DataGrid x:Name="TheDataGrid"
SelectionChanged="TheDataGrid_SelectionChanged"
AutoGenerateColumns="True"
RowEditEnding="TheDataGrid_RowEditEnding"/>
code-behind:
private void TheDataGrid_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0)
{
Message.Text = "The following were removed: ";
foreach (object obj in e.RemovedItems)
{
Customer customer = obj as Customer;
Message.Text += customer.ContactName + ",";
_db.Order_Details.DeleteAllOnSubmit(
customer.Orders.SelectMany(o => o.Order_Details));
_db.Orders.DeleteAllOnSubmit(customer.Orders);
_db.Customers.DeleteOnSubmit(customer);
}
}
try
{
_db.SubmitChanges();
}
catch (Exception ex)
{
Message.Text = ex.Message;
}
}
ANSWER:
Thanks lnferis, that was exactly what I was looking for, here is my finished delete handling event for the datagrid, note the KeyDown event doesn't fire for some reason.
XAML:
<toolkit:DataGrid x:Name="TheDataGrid"
KeyDown="TheDataGrid_KeyDown"
PreviewKeyDown="TheDataGrid_PreviewKeyDown"
AutoGenerateColumns="True"
RowEditEnding="TheDataGrid_RowEditEnding"/>
code-behind
private void TheDataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
var grid = (DataGrid)sender;
if (grid.SelectedItems.Count > 0)
{
string checkMessage = "The following will be removed: ";
foreach (var row in grid.SelectedItems)
{
Customer customer = row as Customer;
checkMessage += customer.ContactName + ",";
}
checkMessage = Regex.Replace(checkMessage, ",$", "");
var result = MessageBox.Show(checkMessage, "Delete", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
foreach (var row in grid.SelectedItems)
{
Customer customer = row as Customer;
_db.Order_Details.DeleteAllOnSubmit(
customer.Orders.SelectMany(o => o.Order_Details));
_db.Orders.DeleteAllOnSubmit(customer.Orders);
_db.Customers.DeleteOnSubmit(customer);
}
_db.SubmitChanges();
}
else
{
foreach (var row in grid.SelectedItems)
{
Customer customer = row as Customer;
LoadData();
_db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer); //TODO: this doesn't refresh the datagrid like the other instance in this code
}
}
}
}
}
private void TheDataGrid_KeyDown(object sender, KeyEventArgs e)
{
Console.WriteLine("never gets here for some reason");
}
The RemovedItems items reflects the items removed from the selection, and not from the grid.
Handle the PreviewKeyDown event, and use the SelectedItems property to delete the selected rows there:
private void PreviewKeyDownHandler(object sender, KeyEventArgs e) {
var grid = (DataGrid)sender;
if ( Key.Delete == e.Key ) {
foreach (var row in grid.SelectedItems) {
... // perform linq stuff to delete here
}
}
}
XAML
<DataGrid ItemsSource="{Binding}" CommandManager.PreviewCanExecute="Grid_PreviewCanExecute" />
Code behind
private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
DataGrid grid = (DataGrid)sender;
if (e.Command == DataGrid.DeleteCommand)
{
if (MessageBox.Show(String.Format("Would you like to delete {0}", (grid.SelectedItem as Person).FirstName), "Confirm Delete", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
e.Handled = true;
}
}
What are you binding your DataGrid to?
Ideally, you should react to CollectionChanged events on the collection you are binding to. That way, your logic (deletion of removed items) will be separated from your UI.
You can build an Observable collection containing your objects and bind it to ItemsSource just for that purpose if the original collection does not have the necessary events.
It might not suit your specific setup, but that's how I usually do it.
Please follow the below code. I have succeeded with the below code.
Please let me know if changes are required.
private void grdEmployee_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Device.Target.GetType().Name == "DataGridCell")
{
if (e.Key == Key.Delete)
{
MessageBoxResult res = MessageBox.Show("Are you sure want to delete?", "Confirmation!", MessageBoxButton.YesNo,MessageBoxImage.Question);
e.Handled = (res == MessageBoxResult.No);
}
}
}
A little late to the party, but to get Inferis answer working:
Dim isEditing = False
AddHandler dg.BeginningEdit, Sub() isEditing = True
AddHandler dg.RowEditEnding, Sub() isEditing = False
AddHandler dg.PreviewKeyDown, Sub(obj, ev)
If e.Key = Key.Delete AndAlso Not isEditing Then ...
This fixes epalms comment: "if you're editing a cell and use the delete key to remove some characters in the cell, you'll end up deleting the whole row"
The cleanest solution is to use PreviewCanExecute like answered by flux, this is a completed solution to make it a bit more clear for anybody that overlooked his answer like I did:
private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (e.Command == DataGrid.DeleteCommand)
{
if (MessageBox.Show($"Delete something from something else?", "Confirm removal of something", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// Do what ever needs to be done when someone deletes the row
}
else
{
e.Handled = true;
// Handled means.. no worries, I took care of it.. and it will not delete the row
}
}
}
No need to hook on to CommandManager.Executed after this.
You want to handle the KeyUp or KeyDown event and check the pressed Key for Delete.
private void OnKeyDown(object sender, KeyEventArgs e) {
if ( Key.Delete == e.Key ) {
// Delete pressed
}
}

Resources