Invoke UIElement’s Focus() Method From ViewModel

One of the things WPF developers often notice is inability to SetFocus on a particular control from the ViewModel. This problem can be however easily resolved using an attached property. Let’s examine the code.

We will begin by writing an attached property, for the purpose of example, named as IsFocused.

public class FocusExtension : DependencyObject
{
    public static bool GetIsFocused(DependencyObject dependencyObject) => (bool)dependencyObject.GetValue(IsFocusedProperty);
    public static void SetIsFocused(DependencyObject dependencyObject, bool value) => dependencyObject.SetValue(IsFocusedProperty, value);
    public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(FocusExtension), new PropertyMetadata(false, IsFocusChanged));
    private static void IsFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
       if ((bool)e.NewValue)
       {
          d as UIElement).Focus();
       }
    }
}

The sole objective of the attached property is to call the Focus() method of the attached UI element when the IsFocused Property Changes. Since the attached property is bindable from ViewModel, we can now set Focus to any control from our View Model. Am using Caliburn.Micro for my MVVM Implementation

View

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox1"/>
        <TextBox Grid.Row="0" Grid.Column="1" Text="TextBox 1" ap:FocusExtension.IsFocused="{Binding IsTextBox1Focused}"  />
        <Button Grid.Row="1" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox2"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="TextBox 2" ap:FocusExtension.IsFocused="{Binding IsTextBox2Focused}"  />
        <Button Grid.Row="2" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox3"/>
        <TextBox Grid.Row="2" Grid.Column="1" Text="TextBox 3" ap:FocusExtension.IsFocused="{Binding IsTextBox3Focused}"  />
        <Button Grid.Row="3" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox4"/>
    </Grid>

ViewModel

public bool IsTextBox1Focused { get; set; }
public bool IsTextBox2Focused { get; set; }
public bool IsTextBox3Focused { get; set; }

public void SetFocusOnTextBox1()
{
   IsTextBox1Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox1Focused));
}

public void SetFocusOnTextBox2()
{
   IsTextBox2Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox2Focused));
}

public void SetFocusOnTextBox3()
{
   IsTextBox3Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox3Focused));
}
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s