I'm going to answer my question with details I've found around StackOverflow.
First of all, I needed to handle the GotFocus and LostFocus events. I didn't want to use the Code Behind, so I found that I could use Interactivity from the System.Windows.Interactivity.dll reference. (From THIS article)
ViewModel:
using System.Windows.Interactivity;
private bool _xFocus;
public ICommand XGotFocus { get; set; }
public ICommand XLostFocus { get; set; }
public ICommand XSend { get; set; }
// In the constructor:
XGotFocus = new RelayCommand(() => _xFocus = true);
XLostFocus = new RelayCommand(() => _xFocus = false);
XSend = new RelayCommand(() => ExecuteXSend());
// Done with constructor
private void ExecuteXSend()
{
RaisePropertyChanged("Xdro");
string sendToPort = "X" + Xdro;
try
{
port.WriteLine(sendToPort);
}
catch (Exception ex)
{
MessageBox.Show("Error: \r\r" + ex.Message);
}
Console.WriteLine("Sending X position: " + sendToPort);
MotorsMoving = true;
RaisePropertyChanged("MotorsMoving");
}
View:
<TextBox x:Name="tbXDro" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" IsReadOnly="False" FontSize="11" MaxLines="1" Text="{Binding Xdro, UpdateSourceTrigger=PropertyChanged}" local:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding XGotFocus, Mode=OneWay}"/>
</i:EventTrigger>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding XLostFocus, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox.InputBindings>
<KeyBinding Command="{Binding XSend}" Key="Return"/>
</TextBox.InputBindings>
</TextBox>
As you can see, I have a key binding for the Return key for the command "XSend". In order to update the Xdro property, THIS article explained a way to update a property when the enter key is pressed.
InputBindingsManager.cs
public static class InputBindingsManager
{
public static readonly DependencyProperty UpdatePropertySourceWhenEnterPressedProperty = DependencyProperty.RegisterAttached(
"UpdatePropertySourceWhenEnterPressed", typeof(DependencyProperty), typeof(InputBindingsManager), new PropertyMetadata(null, OnUpdatePropertySourceWhenEnterPressedPropertyChanged));
static InputBindingsManager()
{
}
public static void SetUpdatePropertySourceWhenEnterPressed(DependencyObject dp, DependencyProperty value)
{
dp.SetValue(UpdatePropertySourceWhenEnterPressedProperty, value);
}
public static DependencyProperty GetUpdatePropertySourceWhenEnterPressed(DependencyObject dp)
{
return (DependencyProperty)dp.GetValue(UpdatePropertySourceWhenEnterPressedProperty);
}
private static void OnUpdatePropertySourceWhenEnterPressedPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
UIElement element = dp as UIElement;
if (element == null)
{
return;
}
if (e.OldValue != null)
{
element.PreviewKeyDown -= HandlePreviewKeyDown;
}
if (e.NewValue != null)
{
element.PreviewKeyDown += new KeyEventHandler(HandlePreviewKeyDown);
}
}
static void HandlePreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
DoUpdateSource(e.Source);
}
}
static void DoUpdateSource(object source)
{
DependencyProperty property =
GetUpdatePropertySourceWhenEnterPressed(source as DependencyObject);
if (property == null)
{
return;
}
UIElement elt = source as UIElement;
if (elt == null)
{
return;
}
BindingExpression binding = BindingOperations.GetBindingExpression(elt, property);
if (binding != null)
{
binding.UpdateSource();
}
}
}
All of this accomplishes the goals:
- Show the position of the motor through the textbox binding
- When the textbox is focused, it is editable and when the Enter/Return key is pressed, it sends the entered value to the Arduino
- It goes back to the DRO view after it has lost focused.
Thanks everyone for all of the help!