As I can understand you need some mechanism to handle user keyboard inputs on a data grid cell. Here what I can suggest you; use an two attached properties. First is a boolean to enable the handling machanism, and the second is an Action tha will support the view model's action to perform the handling itself. You can attach this functionality via DataGridCell's style. Here is a described solution:
1. Xaml:
<Window x:Class="soHelpProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:soHelpProject="clr-namespace:SoHelpProject"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<soHelpProject:MainViewModel/>
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Setter Property="soHelpProject:Attached.IsReactsOnKeyDown" Value="True"></Setter>
<Setter Property="soHelpProject:Attached.OnKeyDownAction" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.OnKeyDownAction}"></Setter>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="120" Binding="{Binding Name}"></DataGridTextColumn>
<DataGridTextColumn Width="120" Binding="{Binding Surname}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid></Window>
2. Attached properties code:
public class Attached
{
public static readonly DependencyProperty OnKeyDownActionProperty = DependencyProperty.RegisterAttached(
"OnKeyDownAction", typeof (Action<object>), typeof (Attached), new PropertyMetadata(default(Action<object>)));
public static void SetOnKeyDownAction(DependencyObject element, Action<object> value)
{
element.SetValue(OnKeyDownActionProperty, value);
}
public static Action<object> GetOnKeyDownAction(DependencyObject element)
{
return (Action<object>) element.GetValue(OnKeyDownActionProperty);
}
public static readonly DependencyProperty IsReactsOnKeyDownProperty = DependencyProperty.RegisterAttached(
"IsReactsOnKeyDown", typeof (bool), typeof (Attached), new PropertyMetadata(default(bool), IsReactsOnKeyDownPropertyChangedCallback));
private static void IsReactsOnKeyDownPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var val = (bool)args.NewValue;
var cell = sender as DataGridCell;
if(cell == null)
return;
if (val == false)
{
cell.KeyDown -= CellOnKeyDown;
}
else
{
cell.KeyDown += CellOnKeyDown;
}
}
private static void CellOnKeyDown(object sender, KeyEventArgs keyEventArgs)
{
var cell = sender as DataGridCell;
if (cell == null)
return;
var action = cell.GetValue(OnKeyDownActionProperty) as Action<object>;
if (action == null) return;
action(keyEventArgs);
}
public static void SetIsReactsOnKeyDown(DependencyObject element, bool value)
{
element.SetValue(IsReactsOnKeyDownProperty, value);
}
public static bool GetIsReactsOnKeyDown(DependencyObject element)
{
return (bool) element.GetValue(IsReactsOnKeyDownProperty);
}
}
3. ViewModel and model code:
public class MainViewModel:BaseObservableObject
{
private Action<object> _onKeyDownAction;
private ObservableCollection<Person> _collection;
public MainViewModel()
{
Collection = new ObservableCollection<Person>
{
new Person
{
Name = "John",
Surname = "A"
},
new Person
{
Name = "John",
Surname = "B"
},
new Person
{
Name = "John",
Surname = "C"
},
};
OnKeyDownAction = new Action<object>(KeyWasPressed);
}
private void KeyWasPressed(object o)
{
var args = o as KeyEventArgs;
if(args == null)
return;
Debug.WriteLine(args.Key.ToString());
}
public Action<object> OnKeyDownAction
{
get { return _onKeyDownAction; }
set
{
_onKeyDownAction = value;
OnPropertyChanged();
}
}
public ObservableCollection<Person> Collection
{
get { return _collection; }
set
{
_collection = value;
OnPropertyChanged();
}
}
}
public class Person:BaseObservableObject
{
private string _name;
private string _surname;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public string Surname
{
get { return _surname; }
set
{
_surname = value;
OnPropertyChanged();
}
}
}
- First of all try to calm down, good job, the application looks well, so is a xaml.
- As I can seen ALL your update logic is based on the PreviewKeyDown, there is still the old value at the moment of 'preview'. Try to base your logic on PreviewKeyUp or on KeyUp when the value is already changed. Let me know if it will help.
I hope this will help you.
Regards,