Set focus on TextBox in WPF from view model
Let me answer to your question in three parts.
I'm wondering what is "cs.txtCompanyID" in your example? Is it a TextBox control? If yes, then you are on a wrong way. Generally speaking it's not a good idea to have any reference to UI in your ViewModel. You can ask "Why?" but this is another question to post on Stackoverflow :).
The best way to track down issues with Focus is... debugging .Net source code. No kidding. It saved me a lot of time many times. To enable .net source code debugging refer to Shawn Bruke's blog.
Finally, general approach that I use to set focus from ViewModel is Attached Properties. I wrote very simple attached property, which can be set on any UIElement. And it can be bound to ViewModel's property "IsFocused" for example. Here it is:
public static class FocusExtension
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool) obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof (bool), typeof (FocusExtension),
new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
private static void OnIsFocusedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement) d;
if ((bool) e.NewValue)
{
uie.Focus(); // Don't care about false values.
}
}
}Now in your View (in XAML) you can bind this property to your ViewModel:
<TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />
Hope this helps :). If it doesn't refer to the answer #2.
Cheers.
How to set Focus to a WPF Control using MVVM?
Generally, when we want to use a UI event while adhering to the MVVM methodology, we create an Attached Property
:
public static DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(TextBoxProperties), new UIPropertyMetadata(false, OnIsFocusedChanged));
public static bool GetIsFocused(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(IsFocusedProperty, value);
}
public static void OnIsFocusedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
TextBox textBox = dependencyObject as TextBox;
bool newValue = (bool)dependencyPropertyChangedEventArgs.NewValue;
bool oldValue = (bool)dependencyPropertyChangedEventArgs.OldValue;
if (newValue && !oldValue && !textBox.IsFocused) textBox.Focus();
}
This property is used like this:
<TextBox Attached:TextBoxProperties.IsFocused="{Binding IsFocused}" ... />
Then we can focus the TextBox
from the view model by changing the IsFocused
property to true
:
IsFocused = false; // You may need to set it to false first if it is already true
IsFocused = true;
How to set focus to textbox using MVVM?
You can do this by adding a property to your ViewModel (or use an existing property) that indicates when the SetFocus should happen but the View should be responsible for actually setting the focus since that is purely View related.
You can do this with a DataTrigger.
View:
<Grid Name="LayoutRoot" DataContext="{StaticResource MyViewModelInstance}">
<Grid.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding UserShouldEditValueNow}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=PropertySearch}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<TextBox Name="PropertySearch" Text="{Binding UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Path=PropertySearch, ValidatesOnDataErrors=True}" Width="110" Height="25" Margin="10" />
</Grid>
ViewModel:
// When you think the view should set focus on a control
this.UserShouldEditValueNow = true;
The example above is simplified by just using a boolean ViewModel property "UserShouldEditValueNow". You can add a property like this to your ViewModel or use some other exising property that indicates this state.
Note: So why is it done this way in MVVM? One reason is, suppose the View author decided to replace the TextBox with a ComboBox, or even better, suppose your property was an integer value that had both a TextBox to view/edit the number and a Slider as another way to edit the same value, both controls bound to the same property... how would the ViewModel know which control to set focus on? (when it shouldn't even know what control, or controls, are bound to it in the first place) This way the View can select which control to focus by changing the ElementName binding target in the DataTrigger Setter.
Happy coding!
MVVM Focus To Textbox
I have documented a "pure MVVM" way to do this in my answer to a similar problem. The solution involves using Attached Properties and a framework for passing interface commands from the ViewModel back to the View.
Setting Focus on TextBox from ViewModel in WPF
If you have a UserControl then you also have CodeBehind.
Place this inside your codebehind and you will do fine.
this.Loaded += (o, e) => { Keyboard.Focus(textBox1) }
Place this inside your UserControl XAML if you wish to listen to validation errors.
<UserControl>
<Grid Validation.Error="OnValidationError">
<TextBox Text{Binding ..., NotifyOnValidationError=true } />
</Grid>
<UserControl>
Inside the CodeBehind of your UserControl you will have something like this:
public void OnValidationError(o , args)
{
if(o is TextBox)
{
(TextBox)o).Text = string.Empty;
}
}
WPF-MVVM: Setting UI control focus from ViewModel
Use the IsFocused Attached Property as suggested in the Answer here: Set focus on textbox in WPF from view model (C#)
Then you can simply bind to a property in your viewmodel.
How to read TextBox focus from ViewModel - MVVM Light
There are several ways how you can achieve this, some of them:
1) Use behavior:
- You need System.Windows.Interactivity.dll
Behavior (setting
IsFocused
property will not make element focused, you need slightly extend behavior in order to achieve this)public class FocusChangedBehavior : Behavior<UIElement>
{
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.Register(
nameof(IsFocused),
typeof(bool),
typeof(FocusChangedBehavior),
new FrameworkPropertyMetadata(default(bool),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public bool IsFocused
{
get { return (bool)this.GetValue(IsFocusedProperty); }
set { this.SetValue(IsFocusedProperty, value); }
}
/// <inheritdoc />
protected override void OnAttached()
{
this.AssociatedObject.GotFocus += this.AssociatedObjectFocused;
this.AssociatedObject.LostFocus += this.AssociatedObjectUnfocused;
}
/// <inheritdoc />
protected override void OnDetaching()
{
this.AssociatedObject.GotFocus -= this.AssociatedObjectFocused;
this.AssociatedObject.LostFocus -= this.AssociatedObjectUnfocused;
}
private void AssociatedObjectFocused(object sender, RoutedEventArgs e)
{
this.IsFocused = true;
}
private void AssociatedObjectUnfocused(object sender, RoutedEventArgs e)
{
this.IsFocused = false;
}
}In XAML you bind
IsFocused
to property in ViewModel.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<TextBox x:Name="textBox1" Text="Text Box 1">
<i:Interaction.Behaviors>
<local:FocusChangedBehavior IsFocused="{Binding IsFocusedTxt1}" />
</i:Interaction.Behaviors>
</TextBox>
<TextBox x:Name="textBox2" Text="Text Box 2">
<i:Interaction.Behaviors>
<local:FocusChangedBehavior IsFocused="{Binding IsFocusedTxt2}" />
</i:Interaction.Behaviors>
</TextBox>Finally in View-Model create properties
public bool IsFocusedTxt1 { get; set; }
public bool IsFocusedTxt2 { get; set; }
2) Alternatively you could you use EventTrigger
in the XAML
- You need System.Windows.Interactivity.dll and MicrosoftExpressionInteractions (For the ActionCommand)
Event Triggers:
<TextBox x:Name="textBox1" Text="Text Box 1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding NotifyFocusedReceivedTxt1Command}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>In ViewModel create command NotifyFocusedReceivedTxt1Command
public ICommand NotifyFocusedReceivedTxt1Command { get; }
// in constructor
this.NotifyFocusedReceivedTxt1Command = new ActionCommand(this.FocusedReceivedTxt1);
// and method
private void FocusedReceivedTxt1()
{
// Your logic
}Also, if you don't want introduce many command/properties you could use same command and pass different textboxes by setting
CommandParameter
(slightly breaks MVVM, but not critically)<TextBox x:Name="textBox1" Text="Text Box 1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding NotifyFocusedReceivedCommand}"
CommandParameter="{Binding ., ElementName=textBox1}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBox x:Name="textBox2" Text="Text Box 2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding NotifyFocusedReceivedCommand}"
CommandParameter="{Binding ., ElementName=textBox2}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>and
public ICommand NotifyFocusedReceivedCommand { get; }
// in constructor
this.NotifyFocusedReceivedCommand = new ActionCommand(this.FocusedReceived);
// and method
private void FocusedReceived(object control)
{
var txt = (TextBox)control;
bool isFocused = txt.IsFocused;
string name = txt.Name;
}
Related Topics
Setting the Default Json Serializer in ASP.NET MVC
Data Binding to Selecteditem in a Wpf Treeview
List≪T≫ or Ilist≪T≫
How Expensive Are Exceptions in C#
Convert Datatable to Json in C#
Line Delimited Json Serializing and De-Serializing
Why Doesn't C# Infer My Generic Types
Why Does Adding a New Value to List≪≫ Overwrite Previous Values in the List≪≫
How to Get Formatted Json in .Net Using C#
How to Find the Number of Cpu Cores Via .Net/C#
Find Control by Name from Windows Forms Controls
.Net Global Exception Handler in Console Application
Setting Authorization Header of Httpclient
Ca2202, How to Solve This Case
A Potentially Dangerous Request.Path Value Was Detected from the Client (*)