When the DataGrid below gets the focus for the first time and only the first time (ie, after some other control has had the focus), the last row, 2nd column should be focused and in edit.
I added a handler for the DataGrid.GotFocus, but it's complicated code and not getting the result above.
Anyone got an elegant, bullet proof solution?
I made tiny modifications to the code
the sender should always be the grid I want, so I just used that instead of relying on a name
When the SelectionUnit is FullRow, as my grid was before I changed it to CellOrRowHeader you
apparently can't call SelectedCells.Clear()
Code below:
private void OnDataGridKeyboardGotFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var dg = sender as DataGrid;
if (_hasHadInitialFocus) return;
var rowIndex = dg.Items.Count - 2;
if (rowIndex >= 0 && dg.Columns.Count - 1 >= 0)
{
var column = dg.Columns[dg.Columns.Count - 1];
var item = dg.Items[rowIndex];
var dataGridCellInfo = new DataGridCellInfo(item, column);
if (dg.SelectionUnit != DataGridSelectionUnit.FullRow) {
dg.SelectedCells.Clear();
dg.SelectedCells.Add(dataGridCellInfo);
}
else {
var row = dg.GetRow(rowIndex);
row.IsSelected = true;
}
dg.CurrentCell = dataGridCellInfo;
dg.BeginEdit();
}
_hasHadInitialFocus = true;
}
New Question
I want to repeat the selection when the focus goes to another control in the window and then back to the grid.
I thought I could turn that _hasHadInitialFocus latch to false in a LostFocus event, but the code below is firing on cell changes.
Do you know how I should be trapping the lost focus event better, and do you agree that is the place to turn the latch off?
private void DataGridLostFocus(object sender, RoutedEventArgs e) {
_hasHadInitialFocus = false;
}
You may have to fiddle with the offsets depending on whether there's an new item row visible or not, but this works for me.
private bool _hasHadInitialFocus;
private void DataGridGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
if (!_hasHadInitialFocus)
{
if (dataGrid.Items.Count - 2 >= 0 && dataGrid.Columns.Count - 1 >= 0)
{
var dataGridCellInfo = new DataGridCellInfo(
dataGrid.Items[dataGrid.Items.Count - 2], dataGrid.Columns[dataGrid.Columns.Count - 1]);
dataGrid.SelectedCells.Clear();
dataGrid.SelectedCells.Add(dataGridCellInfo);
dataGrid.CurrentCell = dataGridCellInfo;
dataGrid.BeginEdit();
}
_hasHadInitialFocus = true;
}
}
I noticed that clicking into the grid leaves one cell selected and the target cell in edit mode. A solution to this if required is:
private void DataGridGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
EditCell();
}
private void PreviewMouseLBDown(object sender, MouseButtonEventArgs e)
{
if (!_hasHadInitialFocus)
{
e.Handled = true;
EditCell();
}
}
private void EditCell()
{
if (!_hasHadInitialFocus)
{
if (dataGrid.Items.Count - 2 >= 0 && dataGrid.Columns.Count - 1 >= 0)
{
var dataGridCellInfo = new DataGridCellInfo(
dataGrid.Items[dataGrid.Items.Count - 2], dataGrid.Columns[dataGrid.Columns.Count - 1]);
dataGrid.SelectedCells.Clear();
dataGrid.SelectedCells.Add(dataGridCellInfo);
dataGrid.CurrentCell = dataGridCellInfo;
dataGrid.BeginEdit();
}
_hasHadInitialFocus = true;
}
}
Related
I have an WPF app using MVVM that shows a log in a ListView control. I have it bound to an ObservableCollection and the control updates when items are added.
I have it coded so that when it starts, it automatically scrolls to the top when an item is inserted into the collection at position 0 so it always shows the latest log message. This works on all machines I have tested.
When a user does something on the ListView (clicks or scrolls), the automatic scrolling is turned off so the user can look at any part of the log they want. When they are finished looking at the log, they can click a button to turn the automatic scrolling back on. Everything works except on one of my test machines, the view changes as items are added. On my dev machine and another test machine, the ListView window does not change when things are added to the collection. Same code/config files are used for all systems.
For example:
The user scrolls to show "My Item" at the top of the ListView.
Another log message is added.
I want "My Item" to still show at the top of the ListView.
Dev machine and one Test machine: "My Item" shows at the top of the ListView.
Another Test Machine: "My Item" is now in the second row of the ListView.
The original change request was because this scrolling was not working on some machines but not others. After much time, there seems to be a difference in the machines themselves that is effecting this.
Is there some system setting that would control this?
XAML:
<ListView Grid.Row="1" Grid.Column="9" Name="messagesListView"
Grid.ColumnSpan="3" Margin="8,0,40,0"
ItemsSource="{Binding StatusMessagesList}"
SelectionChanged="messagesListView_SelectionChanged"
PreviewMouseWheel="messagesListView_PreviewMouseWheel"
MouseDoubleClick="batchesListView_MouseDoubleClick"
PreviewMouseDown="messagesListView_MouseDown"
HorizontalAlignment="Stretch">
</ListView>
Code Behind:
private void ScrollToTop()
{
scrollPos = 0;
ScrollSpot.Text = scrollPos.ToString();
ScrollToPos();
}
private void ScrollToPos()
{
ScrollViewer scrollViewer = GetScrollViewer(messagesListView) as ScrollViewer;
if (scrollViewer != null && _viewState)
scrollViewer.ScrollToVerticalOffset(scrollPos);
}
private void autoScrollButton_Click(object sender, RoutedEventArgs e)
{
messagesListView.SelectedItem = null;
autoScrollButton.Visibility = Visibility.Hidden;
_viewState = true;
ScrollToTop();
}
private void ListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count > 0)
{
ScrollViewer scrollViewer = GetScrollViewer(messagesListView) as ScrollViewer;
if (scrollViewer != null && _viewState)
{
ScrollToTop();
}
if(scrollViewer != null && !_viewState)
{
scrollPos += e.NewItems.Count;
ScrollSpot.Text = scrollPos.ToString();
ScrollToPos();
}
}
}
private void messagesListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_viewState = false;
autoScrollButton.Visibility = Visibility.Visible;
}
private void messagesListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
_viewState = false;
autoScrollButton.Visibility = Visibility.Visible;
}
private void messagesListView_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
{
_viewState = false;
autoScrollButton.Visibility = Visibility.Visible;
}
private void messagesListView_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType().ToString().IndexOf("Rectangle") >= 0)
{
_viewState = false;
autoScrollButton.Visibility = Visibility.Visible;
}
}
Code to Add to Collection:
{
if (_statusMessagesList == null)
StatusMessagesList = new ObservableCollection<string>();
string stMsg = string.Format("{0} {1} {2}", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), message);
StatusMessagesList.Insert(0, stMsg);
Thanks,
Brad P.
Update: I never found out why one system worked and the other did not. However, the solution I found that worked on both was to set messagesListView.CanContentScroll = False
and then manually keep track of the Offset Position on the ScrollViewer:
{
SetUpManualScroll(0);
}
private void messagesListView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
double scrollAmt = (e.Delta / 120) * -48;
SetUpManualScroll(scrollAmt);
}
private void messagesListView_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
{
SetUpManualScroll(e.NewValue);
}
private void messagesListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
SetUpManualScroll(0);
}
private void messagesListView_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType().ToString().IndexOf("TextBlock") < 0 && e.OriginalSource.GetType().ToString().IndexOf("Border") < 0)
{
if (_scrollviewer.VerticalOffset != 0)
SetUpManualScroll(0);
else
{
messagesListView.SelectedItem = null;
autoScrollButton.Visibility = Visibility.Hidden;
_viewState = true;
ScrollToTop();
}
}
}
private void SetUpManualScroll(double d)
{
_viewState = false;
autoScrollButton.Visibility = Visibility.Visible;
_scrollviewer.UpdateLayout();
double newPos = _scrollviewer.VerticalOffset + d;
if (newPos < 0)
newPos = 0;
ScrollPos = newPos;
}
private void ScrollToTop()
{
ScrollPos = 0;
ScrollToPos();
}
private void ScrollToPos()
{
if (_scrollviewer == null)
{
_scrollviewer = GetScrollViewer(messagesListView);
}
_scrollviewer.UpdateLayout();
_scrollviewer.ScrollToVerticalOffset(ScrollPos);
}
Microsoft Blend allows changing numeric values of properties like Left, Top etc. through continuous drag. User clicks in the property value box, keeps the button down and drags left or right to decrease/increase the value. Simple.
The special thing about it is that if cursor reaches the left or right end of the screen and user still wants to drag more, they can continue dragging and the cursor will start over from the other end of the screen.
I'm trying to do this in one of my WPF applications using Thumb control. Using DragDetla event, if I find that the Thumb has reach the edge of the screen, I set its position to the far end. But this makes the value of e.HorizontalChange as big as the width of entire screen. How can I change Thumb's position during drag without affecting horizontal change value?
I have realized this in a WPF control by using a textbox and subscribing to events such as:
PreviewMouseDown
MouseUp and
MouseMove
MouseEnter
The drag until you reach screen limits requires a mouse capture or call to CaptureMouse method available on any UIElement. On the other side, you need to release the mouse at some point which requires a call of the ReleaseMouseCapture method. The solution could go like this:
Declare an enumeration to model the drag direction
internal enum MouseDirections
{
None,
LeftRight,
UpDown
}
Declare a class to keep trak of mouse origin (first location) and current location:
internal class MouseIncrementor
{
private MouseDirections _enumMouseDirection = MouseDirections.None;
private Point _objPoint;
private readonly Point _initialPoint;
public MouseIncrementor(Point objPoint, MouseDirections enumMouseDirection)
{
_objPoint = objPoint;
_initialPoint = _objPoint;
_enumMouseDirection = enumMouseDirection;
}
public MouseDirections MouseDirection
{
get
{
return _enumMouseDirection;
}
protected set
{
_enumMouseDirection = value;
}
}
public Point InitialPoint
{
get
{
return _initialPoint;
}
}
public Point Point
{
get
{
return _objPoint;
}
set
{
_objPoint = value;
}
}
internal MouseDirections SetMouseDirection(Point pos)
{
double deltaX = this.Point.X - pos.X;
double deltaY = this.Point.Y - pos.Y;
if (Math.Abs(deltaX) > Math.Abs(deltaY))
MouseDirection = MouseDirections.LeftRight;
else
{
if (Math.Abs(deltaX) < Math.Abs(deltaY))
MouseDirection = MouseDirections.UpDown;
}
return MouseDirection;
}
}
I have a custom control that contains a TextBox named _PART_TextBox:
TextBox _PART_TextBox;
...and field for the MouseIncrementor:
MouseIncrementor _objMouseIncr;
...these are wired up like this:
_PART_TextBox.MouseEnter += _PART_TextBox_MouseEnter;
_PART_TextBox.GotKeyboardFocus += _PART_TextBox_GotKeyboardFocus;
_PART_TextBox.LostKeyboardFocus += _PART_TextBox_LostKeyboardFocus;
_PART_TextBox.MouseMove += _PART_TextBox_MouseMove;
_PART_TextBox.MouseUp += _PART_TextBox_MouseUp;
_PART_TextBox.PreviewMouseDown += _PART_TextBox_PreviewMouseDown;
_PART_TextBox.LostMouseCapture += _PART_TextBox_LostMouseCapture;
and a number of event handlers are required to get this to work:
private void _PART_TextBox_LostMouseCapture(object sender, MouseEventArgs e)
{
_objMouseIncr = null;
}
private void _PART_TextBox_MouseUp(object sender, MouseButtonEventArgs e)
{
if (_objMouseIncr != null)
{
var mouseUpPosition = GetPositionFromThis(e);
if (_objMouseIncr.InitialPoint.Equals(mouseUpPosition))
{
_PART_TextBox.Focus();
}
}
_PART_TextBox.ReleaseMouseCapture();
_objMouseIncr = null;
}
private void _PART_TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (IsKeyboardFocusWithin == false)
{
_objMouseIncr = new MouseIncrementor(this.GetPositionFromThis(e), MouseDirections.None);
e.Handled = true;
}
}
private void _PART_TextBox_MouseMove(object sender, MouseEventArgs e)
{
// nothing to do here
if (_objMouseIncr == null)
return;
if (e.LeftButton != MouseButtonState.Pressed)
return;
if (CanIncreaseCommand() == false && CanDecreaseCommand() == false)
{
// since we can't parse the value, we are out of here, i.e. user put text in our number box
_objMouseIncr = null;
return;
}
var pos = GetPositionFromThis(e);
double deltaX = _objMouseIncr.Point.X - pos.X;
double deltaY = _objMouseIncr.Point.Y - pos.Y;
if (_objMouseIncr.MouseDirection == MouseDirections.None)
{
// this is our first time here, so we need to record if we are tracking x or y movements
if (_objMouseIncr.SetMouseDirection(pos) != MouseDirections.None)
_PART_TextBox.CaptureMouse();
}
if (_objMouseIncr.MouseDirection == MouseDirections.LeftRight)
{
if (deltaX > 0)
OnDecrement(LargeStepSize);
else
{
if (deltaX < 0)
OnIncrement(LargeStepSize);
}
}
else
{
if (_objMouseIncr.MouseDirection == MouseDirections.UpDown)
{
if (deltaY > 0)
{
if (CanIncreaseCommand() == true)
OnIncrease();
}
else
{
if (deltaY < 0)
{
if (CanDecreaseCommand() == true)
OnDecrease();
}
}
}
}
_objMouseIncr.Point = GetPositionFromThis(e);
}
private Point GetPositionFromThis(MouseEventArgs e)
{
return this.PointToScreen(e.GetPosition(this));
}
private void _PART_TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_objMouseIncr = null;
(sender as TextBox).Cursor = Cursors.ScrollAll;
}
private void _PART_TextBox_MouseEnter(object sender, MouseEventArgs e)
{
if (IsMouseDragEnabled == false)
return;
if (IsKeyboardFocusWithin)
(sender as TextBox).Cursor = Cursors.IBeam;
else
(sender as TextBox).Cursor = Cursors.ScrollAll;
}
private void _PART_TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_objMouseIncr = null;
(sender as TextBox).Cursor = Cursors.IBeam;
}
The full project is located here: https://github.com/Dirkster99/NumericUpDownLib
Please let me know if I am missing something or if there are additional questions.
I try to add a RepositoryItemCheckEdit to my GridView using devexpress and Winforms. However, I can get only one checkbox be checked. If I check another one, the checkbox I checked before becomes unchecked. I followed everything I can find on the net, but couldn't make this work. What am I missing?
The code part I insert the column:
gcIsEmirleri.DataSource = (from i in isemirleri
select new
{
ID = i.isEmriId,
// other attributes
}).ToList();
GridColumn column = gvIsEmirleri.Columns["Sec"];
if (column == null)
{
gvIsEmirleri.BeginUpdate();
DataColumn col = new DataColumn("Sec", typeof(bool));
column = gvIsEmirleri.Columns.AddVisible("Sec");
col.VisibleIndex = 0;
col.Caption = "Sec";
col.Name = "Sec";
col.OptionsColumn.AllowEdit = true;
gvIsEmirleri.EndUpdate();
gvIsEmirleri.Columns["Sec"].UnboundType = DevExpress.Data.UnboundColumnType.Boolean;
RepositoryItemCheckEdit chk = new RepositoryItemCheckEdit();
chk.ValueChecked = true;
chk.ValueUnchecked = false;
gvIsEmirleri.Columns["Sec"].ColumnEdit = chk;
chk.QueryCheckStateByValue += chk_QueryCheckStateByValue;
}
The code part I make the checkbox two-stated instead of three:
private void chk_QueryCheckStateByValue(object sender, DevExpress.XtraEditors.Controls.QueryCheckStateByValueEventArgs e)
{
if (e.Value == null)
{
e.CheckState = CheckState.Unchecked;
e.Handled = true;
}
}
EDIT: I created a List<bool> chkList; and do the following operations:
This function is added to checkedits' CheckStateChanged:
private void chk_CheckStateChanged(object sender, EventArgs e)
{
CheckEdit chk = sender as CheckEdit;
if (chk.Checked)
chkList[gvIsEmirleri.FocusedRowHandle] = true;
else
chkList[gvIsEmirleri.FocusedRowHandle] = false;
FillBindingSource();
}
In FillBindingSource I added the lines:
for (int i = 0; i < chkList.Count; i++)
{
if (chkList[i])
gvIsEmirleri.SetRowCellValue(i, "Sec", true);
}
I debug these lines, I see that List has correct bool values and gvIsEmirleri.SetRowCellValue(i, "Sec", true); is operated when it has to. However, it still doesn't work.
My guess is : You are using an unbound Column, and you are not saving the checked / unckecked info, so, after the selected row is left, the checkBox get it's initial value (unckecked).
For this, I suggest you handle the CustomUnboundColumnData event of your view. Here is a simple :
readonly Dictionary<object, bool> checkedMap = new Dictionary<object, bool>();
private void viewScales_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
{
// Check what column
if (e.Column != gvIsEmirleri.Columns["Sec"])
return;
if (e.IsGetData)
{
// check if the row has been checked and set it's value using e.Value
bool checked;
if (checkedMap.TryGetValue(e.Row, out checked))
e.Value = checked;
}
if (e.IsSetData)
{
var checked = Convert.ToBoolean(e.Value);
// Check if the key already exist
if (checkedMap.ContainsKey(e.Row))
scaleMap.Remove(e.Row);
checkedMap.Add(e.Row, checked);
}
}
Note : This is the way I resolved a similar problem, but I did not test the code I just wrote.
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.
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)