WPF MVVM deselect textbox on Enter key press - c#

What I want is when for the currently focused textbox to lose focus when the user hits the enter key. The only way I can think to achieve this is by using input bindings in XAML to bind to a command in code that passes down the entire textbox control to the viewmodel. I don't like this approach and was hoping someone had a 'clean' way of approaching this problem.

You could create a custom textbox and put this in the controls code:
public partial class CustomTextBox : TextBox
{
public CustomTextBox()
{
InitializeComponent();
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if(e.Key == Key.Return)
Keyboard.ClearFocus();
}
}
Then just use your custom textbox wherever you want that particular behaviour.

Quite often you get a password box on login whereby you need to allow the enter key.
<PasswordBox VerticalAlignment="Center" x:Name="txtPassword" Template="{StaticResource PassBoxBaseControlTemplate}" Height="25" BorderBrush="Black" Width="165.031">
<PasswordBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding ComLoginClickOK}" CommandParameter="{Binding ElementName=txtPassword}"/>
</PasswordBox.InputBindings>
</PasswordBox>

Related

Execute command on textbox when hit enter key

I am new to WPF and I see the best pattern call MVVM. I have try to deep in it and I see that the command can only execute on a button or menuitem, etc. But I have a doubt how to execute the ViewModel command when I'm focusing on a textbox and hit the enter key when I finish my editing.
I have google this but I got nothing from all that answer. So hope all of you help me. How to execute command when hit the enter key in textbox?
In my opinion the easiest way is to use a KeyBinding, which allows you to bind a KeyGesture to an ICommand implementation.
In your case, you can write in your XAML something like this:
<TextBox AcceptsReturn="False">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding YourCommand}" />
</TextBox.InputBindings>
</TextBox>
So when your TextBox is focused and you press Enter, YourCommand will be executed.
I hope it can help you.
You can achieve your requirement using behaviors in WPF.
In XAML,
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TextBox Text="MyText">
<i:Interaction.Behaviors>
<i:BehaviorCollection>
<EventToCommand EventName="TextChanged" Command="{Binding ViewModelCommand}">
**// You can provide other events to be triggered in the EventName property based on your requirement like "Focused" or "UnFocused".Focused event will be fired if you enter into edit mode and UnFocused event will be triggered if you press enter key.**
<i:BehaviorCollection>
</i:Interaction.Behaviors>
</TextBox>
In ViewModel.cs,
Public class ViewModel
{
private Command viewCommand;
public ViewModel()
{
viewCommand = new Command(CommandMethod);
}
public Command ViewModelCommand
{
get { return viewCommand }
set { viewCommand = value}
}
private void CommandMethod()
{
//This method will hit if you modify enter/delete text in the TextBox
}
}

How button name as Backspace work as Backspace for multiple textboxes

On keyboard button name as BackSpace do not work as backspace for multiple textBoxes.
for single textbox i write this code and successfully .
textbox.text = textbox.Text.Remove(textbox.Textlength-1,1);
but not work for multiple textboxes.
Edit Note that this is an WPF answer but the question is about winforms. I'll leave the answer for now in case someone looks for the same thing with WPF.
You can use the FocusManager.IsFocusScope property:
<StackPanel>
<StackPanel x:Name="tbElements" FocusManager.IsFocusScope="True">
<TextBox x:Name="tb1" Margin="3" VerticalAlignment="Top"/>
<TextBox x:Name="tb2" Margin="3" VerticalAlignment="Top"/>
</StackPanel>
<Button Content="Test" Margin="3" Height="26" Click="Button_Click"/>
</StackPanel>
Then the textboxes are managed in a separate logical focus scope
private void Button_Click(object sender, RoutedEventArgs e)
{
var test1 = FocusManager.GetFocusedElement(this);
var test2 = FocusManager.GetFocusedElement(tbElements);
}
The result will be, that test1 references the clicked button, because it has the current focus, but test2 references the last focused textbox, because it has the local focus within its separate logical focus scope.
An alternative would be to set the Button property Focusable to False, so if a textbox has the focus when the button is clicked, the focus stays within the textbox. This prevents keyboard navigation to the button but since the button is part of the screen keyboard, this may be acceptable or even desired behavior.
I am pretty sure that OP does not want to perform backspaces on multiple textboxes, rather wants Backspace button to affect textbox currently focused, so:
To emulate a keyboard stroke use SendKeys.Send(string keys) instead of current implementation. This will perform BACKSPACE on control which has focus:
private void backspace_Click(object sender, EventArgs e)
{
//{BACKSPACE}, {BS}, or {BKSP}
SendKeys.Send("{BACKSPACE}");
}

How to build my own close button?

I have a wpf application with a MVVM. I am trying here to build my own close button. Based on this answer Creating a custom Close Button in WPF I added a button event handler in the View(xaml.cs) code. However, it is not recognizing the Close(); call (doesn't exist in the context - Can't resolve symbol).
Also I tried the other answer and added Command and CommandParameter into my button's xaml. But the function behind is not getting hits. In How to bind Close command to a button using the RelayCommand also my wpf is not recognizing RelayCommand. Then How can I use the RelayCommand in wpf said that I have to write it myself(really?). I remember there was a simple way similar to just set an event handler for the button and call Close();. But, how can I do that or why it is not working for me?
View code:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
// I want to call close the whole app on button click
//Close(); is not recognized
}
private void performMainCloseButtonCommand(object Parameter)
{
// This doesn't get hits on button click
Window objWindow = Parameter as Window;
objWindow.Close();
}
Button XAML:
<Button x:Name="closeButton" RenderTransformOrigin="0.5,0.5" Padding="0" Margin="701,0,0,0" BorderThickness="0" Click="closeButton_Click" Command="{Binding MainCloseButtonCommand}" CommandParameter="{Binding ElementName = mainWindow}" Height="45" Width="45" >
<StackPanel Height="45" Width="45">
<Image x:Name="closeButtonImage" Margin="0" Source="/ProjectName;component/Resources/x.fw.png" Height="33"/>
<TextBlock Text="Close" Width="36" Padding="6,0,0,0" HorizontalAlignment="Center" Height="13" FontSize="10"/>
</StackPanel>
</Button>
Close isn't recognized in your event handler because there is probably no method called Close in your current class. If you want to call main window's close method you can use:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Close();
}
Above is not a good way to do this and does not align with MVVM pattern. Which relates to your second question. Without seeing remaining part of your code, its hard to say why command binding isn't working. My guess you haven't wired up the commands properly for it to fire. You will need to ensure that you have created your RelayCommand instance and your command properties are correctly set.

Set textbox focus after button press

I have the following textbox in a user control.
<!-- This is the user input TextBox, users type commands here and hit enter or press the send command button -->
<TextBox Text="{Binding CommandText}" Background="Transparent" BorderBrush="{StaticResource brushWatermarkBorder}" Name="txtUserEntry">
<TextBox.InputBindings>
<KeyBinding Command="{Binding BindKeyCommand}"
CommandParameter="{Binding ElementName=txtUserEntry, Path=Text}"
Key="Return"
Modifiers=""/>
</TextBox.InputBindings>
</TextBox>
and button.
<!-- This button serves as an alternative to hitting the enter key with text box focus. -->
<Button Command="{Binding BindKeyCommand}" CommandParameter="{Binding ElementName=txtUserEntry, Path=Text}" Grid.Column="2">
<TextBlock>
Send Command
</TextBlock>
</Button>
When a user types into the box and uses the return key too send the command, the command is sent through the BindKeyCommand successfully (a messagebox pops up to confirm this) and focus is maintained on the text box.
However, when a command is sent using the Button, the command is, once again, successful, but the focus on the text box is lost.
I have attempted to implement the answers here but all to no avail. Could someone please explain to me, either, how to correctly implement the answers here, including what to put in the view model, or, an alternative method such that, on button press, the keyboard focus is assigned back to the textbox. It might be important to note, just as in the linked question, I am using MVVM.
UPDATE: Trying to carry out steps by DT Sawant
Step 1:
ApplicationName.Tools.FocusExtension contains all of the text within second highest rated answer. Extension is in namespace ApplicationName.Tools
Step 2:
Added new property;
private bool isTxtUserEntryFocused = false;
public bool IsTxtUserEntryFocused
{
get
{
return isTxtUserEntryFocused;
}
set
{
isTxtUserEntryFocused = value;
OnPropertyChanged("IsTxtUserEntryFocused");
}
}
Step 3:
Added namespace reference; xmlns:Tools ="clr-namespace:WPFLocalDataConnect.Tools"
Step 4:
Bound IsFocused property; Tools:FocusExtension.IsFocused="{Binding IsTxtUserEntryFocused}"
Step 5:
Initializing in viewmodel thusly;
public void ExecuteBindKeyCommand(string param)
{
if (String.IsNullOrWhiteSpace(param))
{
MessageBox.Show("No command given.");
this.CommandText = string.Format("");
IsTxtUserEntryFocused = true;
}
else
{
MessageBox.Show(string.Format("CommandInvoked: {0}", param));
History = string.Format("{0} {2} {1}", History, param, Environment.NewLine);
this.CommandText = string.Format("");
IsTxtUserEntryFocused = true;
}
}
Now all steps are completed I tested the project. It did not work but some interesting things to note;
Pressing the button WITHOUT first focusing the textbox results in "no command" message followed by focus move to textbox. Pressing the button after clicking in the textbox, either entering or not entering text results in "no command" or "command invoked" messages respectively followed by no focus move to the textbox. THIS IS SO CONFUSING.
You can do something like this in code behind to set the focus
<Button Click="MyButton_Click" Name="MyButton" Command="{Binding BindKeyCommand}" CommandParameter="{Binding ElementName=txtUserEntry, Path=Text}" Grid.Column="2" >
<TextBlock>
Send Command
</TextBlock>
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() => txtUserEntry.Focus()));
}
As you have attempted to solve your issue with the help of
this link. I will explain the steps to implement the same solution:
step 1: Add new class FocusExtension as given in above link.
step 2: Add new property IsTxtUserEntryFocused(you can give any name) in your viewmodel
step 3: Add namespace reference of FocusExtension Class in your XAML
step 4: Bind IsFocused property of FocusExtension class to your viewmodel property.
As shown in below:
<TextBox local:FocusExtension.IsFocused="{Binding IsTxtUserEntryFocused}" />
step 5: Now in your button command which you might have implemented in your view model.
Initialize
IsTxtUserEntryFocused=true.
The focus is not retaining on Textbox because your displaying message box.
So focus goes to message box and it does not come back to your window.
You should add this line after your displaying messagebox
Application.Current.MainWindow.Focus();//Bring focus to your window where text box is present
That's it.

Listen for generic events

I have a function I would like to run on after update of a lot of different text boxes, is it possible to listen for a generic after update event rather than the specific events?
So rather than 100 individual calls to the function, just one listener?
Edit: It would appear we are using a combination of MVVM and traditional code behind.
Here is one of the textboxes:
<TextBox Text="{Binding APhaseFrom}" x:Name="txtFromWhereA" TabIndex="26" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Height="48" TextWrapping="NoWrap" VerticalAlignment="Top" Width="261" FontSize="26" FontWeight="Bold" BorderBrush="Black" BorderThickness="1" Margin="289,656,0,0" GotMouseCapture="txtFromWhereA_GotMouseCapture" GotFocus="txtFromWhereA_GotFocus" Grid.Row="3" />
The code from the view Model:
public string APhaseFrom
{
get { return new string((char[])_f.Rows[1].GetValue("Alpha09")); }
set
{
if (value.Length <= 35)
{
_f.Rows[1].SetValue("Alpha09", value);
}
else
{
MessageBox.Show("Error: String length Longer than 35 Characters.");
}
}
}
We also are using some commands for other processes:
public ICommand Updatesql
{
get;
internal set;
}
private void CreateUpdatesql()
{
Updatesql = new RelayCommand(UpdatesqlExecute);
}
private void UpdatesqlExecute()
{
_f.Update();
}
Should I be using commands or just link the events to functions in the viewmodel?
Since you are using WPF, and if I understand your problem correctly, then the RoutedEvents that WPF uses may help you here. Essentially, events like the LostFocus event of a TextBox will bubble up your UI hierarchy and can be handled by a common parent control. Consider this snippet of XAML and codebehind:
<StackPanel TextBox.LostFocus="TextBoxLostFocus">
<TextBox></TextBox>
<TextBox></TextBox>
<TextBox></TextBox>
</StackPanel>
Codebehind:
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
MessageBox.Show("Lost Focus!");
}
You will find that the event handler is called for any of the three textboxes when focus is lost. The sender parameter or e.Source can be used to find the textbox that fired the event.
This pattern holds true for any RoutedEvent, so things like Button.Click or TextBox.TextChanged and many more can be caught in this manner.
Really and truthfully you should be using a single design pattern... ie MVVM when writing WPF applications, each textbox would be bound to a property which implements the INotifyPropertyChange interface.
In the setter of each property you would essentially update the value, fire a property changed event and then either make a call to your method or simply add an event handler on the view model for the PropertyChanged event.
Also... MessageBox.Show is a bad idea in your view models, its hard to unit test it.
Update
I removed my previous ideas because I now understand more clearly what you are looking for.
But you definitely need to use the LostFocus event.
<TextBox Text="{Binding APhaseFrom}" x:Name="txtFromWhereA" LostFocus="OnLostFocus" />

Categories

Resources