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
}
}
Related
I'm inexperienced with both WPF and MVVM so i'm most likeley missing something but when I click my button the command isn't firing. I also have some menu controls on my page that i've setup the exact same way and when I click those, their commands work as expected.
I've tried attaching a click event handler to make sure the button is definitely being clicked which it is. I've also tried attaching a different command that works on my menu control which didn't work on the button.
<Button Grid.Row="1" Content="Add Note"
Command="{Binding InsertNoteCommand}"/>
public ICommand InsertNoteCommand { get; }
public MainViewModel()
{
InsertNoteCommand = new RelayCommand(InsertNote);
}
private void InsertNote()
{
Console.WriteLine("Note Inserted!");
}
I should also mention that i'm using MVVM Light
The debugging information is very useful to know but in the end I solved the problem by pointing the binding to the data context.
<Button x:Name="AddNewNoteBtn" Grid.Row="1" Content="Add Note"
Command="{Binding Path=DataContext.InsertNoteCommand, ElementName=_window}"/>
If anybody has comments on how I can improve this I would really appreciate it. Thanks!
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.
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>
Let's say I currently have an ItemsControl whose DataTemplate is a bunch of buttons. I'm wiring up these buttons' click events, but how am I to know which button was clicked? Should I not use a ItemsControl?
I'm trying to have no code-behind, but being pragmatic may be necessary.
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="10">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding ItemsControlButtonClicked, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to know what Item was clicked, then pass {Binding } as the CommandParameter and it will pass the selected object to your Command
If you want to know what Button was clicked, I would do that in the code-behind since ViewModels do not need to know anything about the UI, and that includes buttons.
Also since your control is a Button, you should use the Command property instead of a Click trigger.
<Button Command="{Binding ItemsControlButtonClicked}" />
You can send parameters along with the command and based on these parameters you can find out which button was clicked
In my project I also use the MVVM Light I has an dropdown with collection of items, and a button which user press and action depend on selected item from drop down
you should create a Relay command with parameter look at the example from my code
public RelayCommand<Project> StartTimer { get; private set; }//declare command
StartTimer = new RelayCommand<Project>(OnStartTimer);
private void OnStartTimer(Project project)
{
if (project != null)
{
currentProject = project;
if (!timer.IsTimerStopped)
{
timer.StopTimer();
}
else
{
Caption = "Stop";
timer.StartTimer();
}
}
on the view I bind the drop down with collection of class Project
and for button command parameter I bind the selected item form drop down
look at the code
<ComboBox Name="projectcomboBox" ItemsSource="{Binding Path=Projects}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="FullName"
SelectedValuePath="Name" SelectedIndex="0" >
</ComboBox>
<Button Name="timerButton" Content="{Binding Path=Caption}" Command="{Binding Path=StartTimer}"
CommandParameter="{Binding ElementName=projectcomboBox, Path=SelectedItem}" ></Button>
pay attention to Command and CommandParameter binding
also you can use this approache not only for drop down
Well, you can use the Sender.DataContext which is the actual data.
Create command properties in your view model class (using Josh Smith's RelayCommand pattern is the simplest way to do this) and bind each button's Command to the appropriate one. Not only is this straightforward to do and simple to maintain, it also gives you an easy way of implementing the enable/disable behavior when you need to.
I'm having trouble getting the RelayCommand to enable/disable the attached control properly.
I've got an EventToCommand element attached to a button. The command is databound to the ViewModel. Initially, the button is disabled (expected behavior), but I cannot seem to get the CanExecute logic to check it's value. When CurrentConfigFile is set and exists, the button should be enabled. I've executed code and checked the file's value in debug to make sure it's set, but the control is still disabled. I've tried CommandManager.InvalidateRequerySuggested() and command.RaiseCanExecuteChanged(), but it will not enable.
I've wondered if lambdas don't work correctly for the CanExecute behavior (even though the examples use them) or that the CanExecute behavior needs to be databound to another element.
Here's my code:
// The FileInfo being checked for existence before the button should be enabled
public const string CurrentConfigFilePN = "CurrentConfigFile";
public FileInfo CurrentConfigFile
{
get
{
return _currentConfigFile;
}
set
{
if (_currentConfigFile == value)
{
return;
}
var oldValue = _currentConfigFile;
_currentConfigFile = value;
// Update bindings, no broadcast
RaisePropertyChanged(CurrentConfigFilePN);
}
}
public MainViewModel()
{
// snip //
SaveCommand = new RelayCommand(SaveConfiguration,
() => CurrentConfigFile != null && CurrentConfigFile.Exists);
}
private void SaveConfiguration()
{
// export model information to xml document
ExportXMLConfiguration(CurrentConfigFile);
}
and markup
<Button x:Name="SaveButton" Content="Save" Width="75" Margin="20,5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<GalaSoft:EventToCommand x:Name="SaveETC"
Command="{Binding SaveCommand}"
MustToggleIsEnabledValue="true" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Update:
As per Isak Savo's suggestion, I bound the RelayCommand directly to the button with
<Button x:Name="SaveButton" Content="Save" Width="75" Margin="20,5"
Command="{Binding SaveCommand}"/>
and it started disabled and correctly enabled when the FileInfo was set. Guess I should remember not to fix what isn't broken!
Why don't you just bind to the Command directly from the Button?
<Button Command="{Binding SaveCommand}" Content="Save" />
Maybe the EventToCommand thing you are using is messing things up with the command's CanExecute notification.
And regarding the CanExecute problem - are you sure that your CanExecute handler is called after the CurrentConfigFile property is set? I've found that even though WPF mostly does a good job of requerying CanExecute, I still sometimes need to force a requery through the CommandManager.
EDIT: As pointed out in the comments, the OP has already tried the command manager approach.
In msdn is written:
When first called, FileInfo calls Refresh and caches information about the file. On subsequent calls, you must call Refresh to get the latest copy of the information.
However, I would not do such a check in the CanExecute-handler. This may slow down your UI because CanExecute is called a lot of times and I could imagine that such IO-checks can become slow, for example if the file lies on a network share.