0

I have some code to set the focused property of a text box, but what i'm actually after is finding out if the text box currently has the keyboard focus, I need to determine this from my view model

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)
    );

    public static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var uie = (UIElement)d;
        if ((bool)e.NewValue)
        {
            uie.Focus();
        }
    }
}

And the xaml is

<TextBox Text="{Binding Path=ClientCode}" c:FocusExtension.IsFocused="{Binding IsClientCodeFocused}" />

source of code

Community
  • 1
  • 1
Rob
  • 1,688
  • 4
  • 30
  • 43
  • 1
    This attached property lets you bind to a boolean DependencyProperty or INPC property in order to set the focus when the property changes. **Where are you trying to find out where it has focus?** –  Aug 12 '11 at 14:41
  • Your ViewModel cares not what is focused. That is the responsibility of the View. [Your question is invalid.](http://i.stack.imgur.com/PBUhJ.jpg) (sorry, didn't want to spend the time changing it from "flag" to "question"). I think your true question should be about what you are trying to accomplish re: your control over what is and is not focused, and how to do this without violating MVVM. –  Aug 12 '11 at 15:11
  • @Will but if I bind a value from my view to my viewmodel this would not break MVVM, which is what i'm trying to do with 'IsClientCodeFocused' - it's declared as bool in my viewmodel – Rob Aug 12 '11 at 15:50
  • Again, the ViewModel cares not what is and what isn't focused, just like it doesn't care where what the mouse cursor is hovering, what the current screen resolution is, etc etc. This should be handled in the View's xaml or codebehind. Honestly, whatever you are doing is probably going to be much harder to accomplish trying to get the ViewModel to handle it. –  Aug 12 '11 at 16:10

3 Answers3

1

have you seen the FocusManager? you can get/set focus using this object.

Muad'Dib
  • 28,542
  • 5
  • 55
  • 68
0

Edit

Based on the comments below, here's an example of an attached property that hooks up an event and updates the source of a binding. I'll add comments where I know you'll need to make modifications. Hopefully it will point you in the right direction

public class TextBoxHelper
{
    // I excluded the generic stuff, but the property is called 
    // EnterUpdatesSource and it makes a TextBox update it's source
    // whenever the Enter key is pressed

    // Property Changed Event - You have this in your class above
    private static void EnterUpdatesTextSourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        UIElement sender = obj as UIElement;
        if (obj != null)
        {
            // In my case, the True/False value just determined a behavior,
            // so toggling true/false added/removed an event.

            // Since you want your events to be on at all times, you'll either
            // want to have two AttachedProperties (one to tell the control
            // that it should be tracking the current focused state, and 
            // another for binding the actual focused state), or you'll want 
            // to find a way to only add the EventHandler when the 
            // AttachedProperty is first added and not toggle it on/off as focus 
            // changes or add it repeatedly whenever this value is set to true

            // You can use the GotFocus and LostFocus Events
            if ((bool)e.NewValue == true)
            {
                sender.PreviewKeyDown += new KeyEventHandler(OnPreviewKeyDownUpdateSourceIfEnter);
            }
            else
            {
                sender.PreviewKeyDown -= OnPreviewKeyDownUpdateSourceIfEnter;
            }
        }
    }

    // This is the EventHandler
    static void OnPreviewKeyDownUpdateSourceIfEnter(object sender, KeyEventArgs e)
    {
        // You won't need this
        if (e.Key == Key.Enter)
        {
            // or this
            if (GetEnterUpdatesTextSource((DependencyObject)sender))
            {
                // But you'll want to take this bit and modify it so it actually 
                // provides a value to the Source based on UIElement.IsFocused
                UIElement obj = sender as UIElement;

                // If you go with two AttachedProperties, this binding should 
                // point to the property that contains the IsFocused value
                BindingExpression textBinding = BindingOperations.GetBindingExpression(
                    obj, TextBox.TextProperty);

                // I know you can specify a value for a binding source, but
                // I can't remember the exact syntax for it right now
                if (textBinding != null)
                    textBinding.UpdateSource();
            }
        }
    }

There might be a better way of accomplishing what you're trying to do, but if not then I hope this provides a good starting point :)

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • I'm not sure if this would be accessible from my viewmodel – Rob Aug 12 '11 at 14:39
  • @Rob Wouldn't your ViewModel's `IsClientCodeFocused` contain if it has focus or not? Wait I think I see what you're after.... You'll want to hook up a `FocusChanged` event to update the binding source in your AttachedProperty when it gets set to a value. – Rachel Aug 12 '11 at 14:47
  • that sounds good! unfortunately I have no idea how to do that, should that be in the FocusExtension class or in the view or even in the view model? – Rob Aug 12 '11 at 14:58
  • lol The easiest way would be in the code-behind the view, but you'd have to do that every time you use the extension. The most efficient way would be in the `FocusExtension` class. I'm not positive how you would go about doing that, but I can post another AttachedProperty class that I've used before which you can hopefully use as a starting point. – Rachel Aug 12 '11 at 15:01
0

in your OnIsFocusedPropertyChanged handler, you need to get a reference to the control that it is being set on and subscribe to its FocusChanged event, where you can re-set the dependency pproperty. Make sure in your XAML you set the binding mode to TwoWay

Dean Chalk
  • 20,076
  • 6
  • 59
  • 90