It appears that if the cell is in edit mode, the custom command provider does not pick up the keyboard events. If I press ESC to cancel edit mode, then the provide gets called. Is there some problem with how I have defined my XAML? I would expect the "Key.Up" and "Key.Down" keys to propogate through the edit control (TextBox) and through to the command provider. Here's what the XAML looks like for the column I'm testing:
<trgv:GridViewDataColumn Header="Quantity"
MinWidth="75"
HeaderTextAlignment="Right"
ShowDistinctFilters="False">
<trgv:GridViewDataColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Quantity}"
HorizontalAlignment="Right"/>
</DataTemplate>
</trgv:GridViewDataColumn.CellTemplate>
<trgv:GridViewDataColumn.CellEditTemplate>
<DataTemplate>
<infctrl:NumberTextBox Value="{Binding Quantity, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}"
HorizontalAlignment="Stretch"
DisplayFormat="N0"/>
</DataTemplate>
</trgv:GridViewDataColumn.CellEditTemplate>
</trgv:GridViewDataColumn>
16 Answers, 1 is accepted
Following up the example in the blog post, the edit-mode of the cell is not propagated on using Key.Up and Key.Down in case the Clear() method is called upon the commandsToExecute. Otherwise, the mode of the cell is normally transferred to the next/previous ones.
So, in order to provide you with an appropriate solution, I would need a bit more information about the behavior you want to achieve on navigating with the Up and Down keys.
Maya
the Telerik team
See the attached images for more information. Here's the explanation:
In the image StateA, the cursor is in the first row of the Quantity column and the cell is in edit mode. The column is defined in XAML like this:
<
trgv:GridViewDataColumn
Header
=
"Quantity"
MinWidth
=
"75"
HeaderTextAlignment
=
"Right"
ShowDistinctFilters
=
"False"
>
<
trgv:GridViewDataColumn.CellTemplate
>
<
DataTemplate
>
<
TextBlock
Text
=
"{Binding Quantity}"
HorizontalAlignment
=
"Right"
/>
</
DataTemplate
>
</
trgv:GridViewDataColumn.CellTemplate
>
<
trgv:GridViewDataColumn.CellEditTemplate
>
<
DataTemplate
>
<
infctrl:NumberTextBox
Value
=
"{Binding Quantity, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}"
HorizontalAlignment
=
"Stretch"
DisplayFormat
=
"N0"
/>
</
DataTemplate
>
</
trgv:GridViewDataColumn.CellEditTemplate
>
</
trgv:GridViewDataColumn
>
You will notice that I'm using a custom control for the edit control. This control derives from TextBox and add some additional features such as numeric formatting and automatica justification when the control receives and loses focus. Even if I change this to a regular TextBox the problem still exists.
What I want to happen is when the user presses the down arrow key, the currently edited cell should commit edit mode, the cursor moves to the next row / same column and that cell is put into edit mode (see StateB image).
Now, this is an editable column. I also have read-only columns so if the user presses the left or right arrow to move from an editable column to a read-only column, the cell being moved to should not be put into edit mode. I believe I can determine this in my custom keyboard command provider by checking the IsReadOnly property of the CurrentColumn property of the grid.
Here's the current implementation of my custom keyboard command provider:
public
class
OrderDetailsKeyboardCommandProvider : DefaultKeyboardCommandProvider
{
GridViewDataControl _grid;
public
OrderDetailsKeyboardCommandProvider(GridViewDataControl grid) :
base
(grid)
{
_grid = grid;
}
public
override
IEnumerable<System.Windows.Input.ICommand> ProvideCommandsForKey(System.Windows.Input.Key key)
{
List<ICommand> commandsToExecute =
base
.ProvideCommandsForKey(key).ToList();
if
(key == Key.Up)
{
commandsToExecute.Clear();
if
((_grid.CurrentColumn.IsReadOnly ==
false
) && (_grid.CurrentCell.IsInEditMode))
commandsToExecute.Add(RadGridViewCommands.CommitEdit);
commandsToExecute.Add(RadGridViewCommands.MoveUp);
commandsToExecute.Add(RadGridViewCommands.SelectCurrentUnit);
if
(_grid.CurrentColumn.IsReadOnly ==
false
)
commandsToExecute.Add(RadGridViewCommands.BeginEdit);
}
if
(key == Key.Down)
{
commandsToExecute.Clear();
if
((_grid.CurrentColumn.IsReadOnly ==
false
) && (_grid.CurrentCell.IsInEditMode))
commandsToExecute.Add(RadGridViewCommands.CommitEdit);
commandsToExecute.Add(RadGridViewCommands.MoveDown);
commandsToExecute.Add(RadGridViewCommands.SelectCurrentUnit);
if
(_grid.CurrentColumn.IsReadOnly ==
false
)
commandsToExecute.Add(RadGridViewCommands.BeginEdit);
}
return
commandsToExecute;
}
}
The problem is that it appears the RoutedUICommand of the Key.Down / Key.Up is not being propogated to my keyboard command provider from the TextBox control used to edit the cell value. If I set a breakpoint on the first line of the ProvideCommandsForKey override it does not get hit. I suspect that somewhere we need to look at the PreviewKeyDown event rather than the KeyDown event.
The reason for this behavior is indeed the TextBox that does not handle the KeyDown event. Thus the logic for setting the cell above/below in edit-mode or not is not applied. However, this is caused by the WPF native TextBox and event if you define Custom KeyboardCommandProvider, you will not be able to achieve the desired result.
What you can do is to create your own custom column, whose element handles the KeyDown event and set the cell into edit-mode. You can find an example of adding a custom column in this blog post.
Maya
the Telerik team
I'm not sure this will solve my problem. As I stated, when the down or up arrow is pressed while in a column that is in edit mode, I need to cancel (or commit) editing, move up or down and then put the next column into edit mode. I need to use a TextBox-based control so your suggestion to "create your own custom column, whose element handles the KeyDown event and set the cell into edit-mode" doesn't make sense. Do you have a concrete example of how to do EXACTLY what I require? The blog post about creating a custom column does not refer at all to the handling of key presses.
This has become a critical issue for me moving forward on a project so I would appreciate a quick response.
Regards,
Dave
The restriction with the edit-mode when navigating comes from the regular TextBox that handles the KeyDown event. However, you can handle the PreviewKeyDown event and define the behavior of the grid on Left/Right/Up/Down Keys using a sequence of commands.
For example, the code for the Left Key will be as follows:
private void HandleKeyLeft(KeyEventArgs e)
{
if (e.Key == Key.Left)
{
var editBox = this.playersGrid.CurrentCell.ChildrenOfType<
TextBox
>().FirstOrDefault();
if (editBox.CaretIndex == 0)
{
RadGridViewCommands.MoveLeft.Execute(null);
RadGridViewCommands.SelectCurrentUnit.Execute(null);
RadGridViewCommands.BeginEdit.Execute(null);
e.Handled = true;
}
}
}
The condition of (editBox.CaretIndex=0) ensures that you are in the beginning of the TextBox and you need to go to the previous cell.
I am sending you a sample project demonstrating the implementation of that functionality.
Sincerely yours,
Maya
the Telerik team
THANK YOU! This is EXACTLY what I needed.
Cheers,
Dave
I added a Salary property to Player like this:
public
double
Salary
{
get
{
return
this
.salary; }
set
{
if
(value !=
this
.salary)
{
this
.salary = value;
this
.OnPropertyChanged(
"Salary"
);
}
}
}
And here's the column definitions:
<
telerik:RadGridView.Columns
>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Name}"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Number}"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Position}"
/>
<
telerik:GridViewMaskedTextBoxColumn
DataMemberBinding
=
"{Binding Salary}"
MaskType
=
"Numeric"
Mask
=
"c"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Country}"
/>
</
telerik:RadGridView.Columns
>
Please let me know how to work around this issue.
You can try to use the MovePrevious and MoveNext Commands instead of MoveLeft and MoveRight. In this way, once the cell in edit mode is the first/last one, navigating with the Arrow Keys will lead you to the previous/next cell, which will be again in edit mode.
Maya
the Telerik team
Up, down and left keys work fine. Right arrow does not. I believe this is related to PITS # 3436
You can make a slight change when handling the event for that key and set it as follows:
private void HandleKeyLeft(KeyEventArgs e)
{
if (e.Key == Key.Left)
{
var editBox = this.playersGrid.CurrentCell.ChildrenOfType<
TextBox
>().FirstOrDefault();
if (editBox.CaretIndex == 0 && editBox.SelectionLength == 0)
{
RadGridViewCommands.MovePrevious.Execute(null);
RadGridViewCommands.SelectCurrentUnit.Execute(null);
RadGridViewCommands.BeginEdit.Execute(null);
e.Handled = true;
}
}
}
Regards,
Maya
the Telerik team
Firstly, please excuse me for the misunderstanding. Indeed the issue here conserns the one you pointed.Unfortunately, it has not been resolved yet.
However, as a possible workaround, I may suggest to you to use a GridViewDataColumn and set its DataFormatString Property. For example:
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Salary}"
DataFormatString
=
"{}{0:c}"
/>
I hope that helps.
Sincerely yours,
Maya
the Telerik team
We want to provide some custom behaviour based upon some Key combination e.g. Control + C. But when Control is pressed we always get Control in the key. So we can not determine the combination.
Please suggest.
Thanks
Vinay
You may handle the PreviewKeyDown event of the grid as follows:
public MainWindow()
{
InitializeComponent();
this.clubsGrid.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(clubsGrid_PreviewKeyDown);
void clubsGrid_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.C)
{
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MessageBox.Show("Control+C keys are pressed");
}
}
}Kind regards,
Maya
the Telerik team
With the current version, you can try defining the key down method as follows:
private void HandleKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Down)
{
RadGridViewCommands.CommitEdit.Execute(null);
RadGridViewCommands.MoveDown.Execute(null);
RadGridViewCommands.SelectCurrentUnit.Execute(null);
this.Dispatcher.BeginInvoke((Action)(() => RadGridViewCommands.BeginEdit.Execute(null)), System.Windows.Threading.DispatcherPriority.Input);
e.Handled = true;
}
}
Regards,
Maya
Telerik