How can I set focus on a TextBox when F3 key pressed.
In other words, do some thing like bellow:
private void Window_PreviewKeyDown(object sender, KeyEventArgs )
{
switch (e.Key)
{
case Key.F3:
myTextBox1.Focus();
break;
case Key.F4:
myTextBox2.Focus();
break;
default:
break;
}
}
note:I want to do it in xaml.
You could do this by created an attached property that takes a shortcut key then create an input binding on the window hosting that control.. it's a bit of a complex class but very easy to use.
start by adding a new class to your project below.
public class TextBoxHelper : DependencyObject
{
public class MvvmCommand : DependencyObject, ICommand
{
readonly Action<object> _execute;
readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public MvvmCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
if (execute == null) throw new ArgumentNullException("command");
_canExecute = canExecute == null ? parmeter => MvvmCommand.AlwaysCanExecute() : canExecute;
_execute = execute;
}
public object Tag
{
get { return (object)GetValue(TagProperty); }
set { SetValue(TagProperty, value); }
}
public static readonly DependencyProperty TagProperty = DependencyProperty.Register("Tag", typeof(object), typeof(MvvmCommand), new PropertyMetadata(null));
static bool AlwaysCanExecute()
{
return true;
}
public void EvaluateCanExecute()
{
EventHandler temp = CanExecuteChanged;
if (temp != null)
temp(this, EventArgs.Empty);
}
public virtual void Execute(object parameter)
{
_execute(parameter == null ? this : parameter);
}
public virtual bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
}
public static Key GetFocusKey(DependencyObject obj)
{
return (Key)obj.GetValue(FocusKeyProperty);
}
public static void SetFocusKey(DependencyObject obj, Key value)
{
obj.SetValue(FocusKeyProperty, value);
}
public static readonly DependencyProperty FocusKeyProperty =
DependencyProperty.RegisterAttached("FocusKey", typeof(Key), typeof(TextBoxHelper), new PropertyMetadata(Key.None, new PropertyChangedCallback((s, e) =>
{
UIElement targetElement = s as UIElement;
if (targetElement != null)
{
MvvmCommand command = new MvvmCommand(parameter => TextBoxHelper.FocusCommand(parameter))
{
Tag = targetElement,
};
InputGesture inputg = new KeyGesture((Key)e.NewValue);
(Window.GetWindow(targetElement)).InputBindings.Add(new InputBinding(command, inputg));
}
})));
public static void FocusCommand(object parameter)
{
MvvmCommand targetCommand = parameter as MvvmCommand;
if (targetCommand != null)
{
UIElement targetElement = targetCommand.Tag as UIElement;
if (targetElement != null)
{
targetElement.Focus();
}
}
}
}
now in XAML all you need to do to set your focus keys is assign that FocusKey property, an example below has 2 textboxes, one gets focus when F1 is pressed, the other when F7 is pressed.
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication5"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="131" Width="460">
<Grid Margin="10">
<TextBox Margin="0,0,0,60" local:TextBoxHelper.FocusKey="F1" />
<TextBox Margin="0,35,0,0" local:TextBoxHelper.FocusKey="F7" />
</Grid>
</Window>
Related
I have two methods that do almost the two things:
public static void ShowThing()
{
// code..
}
and
public static bool TryShowThing()
{
if(condition)
{
// same code above..
return true;
}
return false;
}
At the moment I'm binding a button's Command to the void method and it does what it should.
Problem is that now I'm cleaning up the code and to avoid coupling I wanted to bind the button to the bool method and that won't work.
Is Command={Binding BooleandReturningMedhod} even allowed in xaml?
Apparently nobody on the internet has ever had this problem before so I think I'm missing something here...
You cannot bind directly to a method.
What i think what you really wanna achieve is something like this
Code:
ShowThingCommand { get; } = new RelayCommand((o) => ShowThing(),(o) => condition)
RelayCommand:
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
XAML:
<Button Command={Binding ShowThingCommand } />
Important part is the CanExecute method, when it returns false your Button gets disabled
Since CaretIndex of TextBox control is not a DependencyProperty, how do I get the value of CaretIndex in the ViewModel?
You can you Interaction.Behaviors create your own behaviour and get the property you want from it.
For eg. this is a EventCommandConverterBehavior. Using it will return the property value which you specify from xaml, and if property name is not set. it will return Corresponding EventArgs
public class EventCommandConverterBehavior : Behavior<FrameworkElement>
{
private Delegate eventHandler;
private EventInfo oldEvent;
// Event
public string EventName { get { return (string)GetValue(EventNameProperty); } set { SetValue(EventNameProperty, value); } }
public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(EventCommandConverterBehavior), new PropertyMetadata(null, OnEventChanged));
// Command
public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommandConverterBehavior), new PropertyMetadata(null));
public string PropertyName { get { return (string)GetValue(PropertyNameProperty); } set { SetValue(PropertyNameProperty, value); } }
public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register("PropertyName", typeof(string), typeof(EventCommandConverterBehavior), new PropertyMetadata());
private static void OnEventChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var behavior = (EventCommandConverterBehavior)dependencyObject;
if (behavior.AssociatedObject != null)
behavior.AttachHandler((string)args.NewValue);
}
protected override void OnAttached()
{
AttachHandler(this.EventName);
}
private void AttachHandler(string eventName)
{
// detach old event
if (this.oldEvent != null)
this.oldEvent.RemoveEventHandler(this.AssociatedObject, this.eventHandler);
// attach new event
if (string.IsNullOrEmpty(eventName))
{
return;
}
var eventInfo = this.AssociatedObject.GetType().GetEvent(eventName);
if (eventInfo != null)
{
var methodInfo = this.GetType()
.GetMethod("CommandExecuter", BindingFlags.Instance | BindingFlags.NonPublic);
this.eventHandler = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, methodInfo);
eventInfo.AddEventHandler(this.AssociatedObject, this.eventHandler);
this.oldEvent = eventInfo;
}
else
throw new ArgumentException(string.Format("Type {0} does not contain event {1} definition.",
this.AssociatedObject.GetType().Name, eventName));
}
private void CommandExecuter(object sender, EventArgs e)
{
object parameter = null != PropertyName ? GetPropValue(sender, PropertyName) : e;
if (this.Command != null)
{
if (this.Command.CanExecute(parameter))
this.Command.Execute(parameter);
}
}
public static object GetPropValue(object src, string propName)
{
var propertyInfo = src.GetType().GetProperty(propName);
return propertyInfo != null ? propertyInfo.GetValue(src, null) : null;
}
}
In Xaml you have to write
<TextBox Name="TextBox1" Text="SomeText" Height="20" Width="60">
<i:Interaction.Behaviors >
<wpfPractice:EventCommandConverterBehavior Command="{Binding PropertyValueCommand}" EventName="SelectionChanged" PropertyName="CaretIndex" />
</i:Interaction.Behaviors>
</TextBox>
Where PropertyValueCommand shold be a command in DataContext(i.e. ViewModel.
let me know if it works.
Simple RelayCommand defined as follows:
public class RelayCommand : IDelegateCommand
{
readonly Predicate<object> _canExecute;
readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
: this(canExecute, execute, true)
{
}
public RelayCommand(Predicate<object> canExecute, Action<object> execute, bool isCommandAllowed)
{
_canExecute = canExecute;
_execute = execute;
IsAllowed = isCommandAllowed;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
public virtual bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged = delegate { };
public virtual void Execute(object parameter)
{
_execute(parameter);
}
IDelegateCommand is defined as follows:
public interface IDelegateCommand : ICommand
{
void RaiseCanExecuteChanged();
}
Is bound to a WPF Button as follows:
<Button Command="{Binding StartSimulationCommand}" Content="Start Simulation"/>
And corresponding ViewModel usage of the Command is given as follows:
public class MainViewModel
{
// missing irrelevant bits
public ICommand StartSimulationCommand
{
get { return new RelayCommand(arg => true, arg =>
{
var inputValidationResponse = ValidateInputs();
if (!string.IsNullOrEmpty(inputValidationResponse))
{
_logger.Error(inputValidationResponse);
return;
}
// this method opens a websocket and if that operation is
// successful, property called IsWebSocketOpen is updated.
OpenWebSocketChannel();
// update command states
StopSimulationCommand.RaiseCanExecuteChanged();
});
}
}
public RelayCommand StopSimulationCommand
{
get { return new RelayCommand(arg => IsWebSocketOpened, arg => { CloseWebSocketChannel(); }); }
}
private bool _isWebSocketOpened;
public bool IsWebSocketOpened {
get { return _isWebSocketOpened; }
set { SetField(ref _isWebSocketOpened, value, "IsWebSocketOpened"); }
}
}
When I invoke StopSimulationCommand.RaiseCanExecuteChanged, the state of the button bound to StopSimulationCommand does not changed to enabled, even through the predicate for that command now returns true.
What did I miss?
You are creating a new instance of the RelayCommand in the setter of the StopSimulationCommand. You should create the command once in the constructor of the view model class:
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel ()
{
StopSimulationCommand = new RelayCommand(arg => IsWebSocketOpened, arg => { CloseWebSocketChannel(); });
}
public RelayCommand StopSimulationCommand { get; private set; }
}
I have created a TextBox that implements ICommandSource, for the most part I followed Microsoft's example using a Slider. This TextBox will execute the bound command upon pressing the "Enter" key. This portion of the behavior is working correctly, the issue I am having is that IsEnabled can no longer be set in XAML? I am not sure why this is, you can still set IsEnabled on native Microsoft classes like Button.
public class CommandTextBox : TextBox, ICommandSource
{
// The DependencyProperty for the Command.
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandTextBox), new PropertyMetadata(OnCommandChanged));
// The DependencyProperty for the CommandParameter.
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandTextBox));
// The DependencyProperty for the CommandTarget.
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CommandTextBox));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public bool CommandResetsText { get; set; }
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
// Command dependency property change callback.
private static void OnCommandChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
CommandTextBox ctb = (CommandTextBox)dp;
ctb.HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
}
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
RemoveCommand(oldCommand);
AddCommand(newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand command)
{
EventHandler handler = CanExecuteChanged;
command.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand command)
{
var handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (command != null)
command.CanExecuteChanged += canExecuteChangedHandler;
}
private void CanExecuteChanged(object sender, EventArgs e)
{
if (Command != null)
{
RoutedCommand command = Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
this.IsEnabled = true;
else
this.IsEnabled = false;
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
this.IsEnabled = true;
else
this.IsEnabled = false;
}
}
}
// If Command is defined, pressing the enter key will invoke the command;
// Otherwise, the textbox will behave normally.
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Enter)
{
if (Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
command.Execute(CommandParameter, CommandTarget);
else
Command.Execute(CommandParameter);
if (CommandResetsText)
this.Text = String.Empty;
}
}
}
private EventHandler canExecuteChangedHandler;
}
XAML
<Button Command="{Binding GenericCommand}" IsEnabled="False" /> // This is disabled(desired).
<CommandTextBox Command="{Binding GenericCommand}" IsEnabled="False" /> // This is enabled?
Any feedback would be appreciated.
First, you need to create a private property or a field that will be set if the command can execute:
private bool _canExecute;
Second, you need to override IsEnabledCore property:
protected override bool IsEnabledCore
{
get
{
return ( base.IsEnabledCore && _canExecute );
}
}
And finally, you just fixing CanExecuteChanged method by replacing IsEnabled with _canExecute and coercing IsEnabledCore after all:
private void CanExecuteChanged(object sender, EventArgs e)
{
if (Command != null)
{
RoutedCommand command = Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
_canExecute = command.CanExecute(CommandParameter, CommandTarget);
}
// If a not RoutedCommand.
else
{
_canExecute = Command.CanExecute(CommandParameter);
}
}
CoerceValue(UIElement.IsEnabledProperty);
}
I need to disable button for a while it running. I have this code:
RelayCommand.cs This is my command class.
class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
MainWindowViewModel.cs This is my command for binding.
private RelayCommand _getTextCommand;
public ICommand GetTextCommand
{
get
{
if (_getTextCommand == null)
{
_getTextCommand = new RelayCommand(
param => this.GetText(param),
param => true
);
}
return _getTextCommand;
}
}
MainWindow.xaml This is XAML code where i bind my command.
<Button x:Name="getTextButton" Command="{Binding GetTextCommand}" CommandParameter="{Binding ElementName=textTypeSelector, Path=SelectedIndex}"/>
This is the code i am launching in command:
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
// code
});
}
Try this: add a boolean property in view model and implement INotifyPropertyChanged in view model
private bool isEnable = true;
public bool IsEnable
{
get { return isEnable; }
set
{
isEnable = value;
NotifyPropertyChanged();
}
}
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
IsEnable = false;
});
IsEnable = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Bind it to button IsEnable property
<Button x:Name="abc"
Command="{Binding GetTextCommand}"
IsEnabled="{Binding IsEnable}" />
Set IsEnable whereever you want.
Add a boolean to your ViewModel to indicate that the command is executing and set the boolean in your GetText() method.
private bool _isRunning = false;
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
_isRunning = true;
CommandManager.InvalidateRequerySuggested();
// code
_isRunning = false;
CommandManager.InvalidateRequerySuggested();
});
}
public bool CanGetText(object o){
return ! _isRunning;
}
Then change your RelayCommand to the following
_getTextCommand = new RelayCommand(this.GetText,CanGetText);
The problem is that you are passing true for the CanExecute delegate. Pass it a method that will execute every time it needs evaluation, and within that method you can test to see whether the Command should be executable or otherwise.
Here is an implementation that I'm using. It doesn't need an additional property in the ViewModel.
public sealed class AsyncDelegateCommand : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Func<Task> _executeAsync;
private Task _currentExecution;
public AsyncDelegateCommand(Func<Task> executeAsync)
: this(executeAsync, null)
{
}
public AsyncDelegateCommand(Func<Task> executeAsync, Func<bool> canExecute)
{
if (executeAsync == null) throw new ArgumentNullException("executeAsync");
_executeAsync = executeAsync;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
if (_currentExecution != null && !_currentExecution.IsCompleted)
{
return false;
}
return _canExecute == null || _canExecute();
}
public async void Execute(object parameter)
{
try
{
_currentExecution = _executeAsync();
await _currentExecution;
}
finally
{
_currentExecution = null;
CommandManager.InvalidateRequerySuggested();
}
}
}