0

I am using MVVM for my application and have a form that allows the user to enter basic personnel information. The form includes a UserControl which is, basically, an ItemsControl that includes textBoxes that can be dynamically created. This is a simplified version:

<ItemsControl x:Name="items" ItemsSource="{Binding MyItemsCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid x:Name="row">
                <TextBox x:Name="textBox" Text="{Binding ContactInfo, ValidatesOnExceptions=True}" extensions:FocusExtension.IsFocused="{Binding IsFocused}"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
<Button x:Name="NewItemButton" Command="{Binding AddItemToMyCollectionCommand}" />

I want the TextBox that has just been created to receive focus, therefore I added an attached property. This is part of it:

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

In the form that contains the UserControl there are several other text boxes before and after. The UserControl has its own ViewModel, which I set as the DataContext of the control through a property in the container's ViewModel. Basically, a simplified version of the container looks like this:

<StackPanel Orientation="Horizontal" />
    <TextBox x:Name="firstName" />
    <TextBox x:Name="lastName" />
    <local:DynamicFormUserControl
        x:Name="phones"
        DataContext="{Binding PhonesViewModel}" />
    <local:DynamicFormUserControl
        x:Name="emails"
        DataContext="{Binding EmailsViewModel}" />
    <TextBox x:Name="address" />
</StackPanel>

My problem is that I want the firstName TextBox to get the focus when the form is loaded for the first time, but the form keeps on placing the focus on the first TextBox of the phones UserControl. I tried to override it by using firstName.Focus() on the Loaded event of the form, but this didn't work, and no matter what I tried the focus is still on the phones userControl instead of the first element in the form that contains it.

Does anybody have any idea how to solve this?

Thanks.

ppalms
  • 394
  • 2
  • 7
  • 19
user2921009
  • 711
  • 1
  • 10
  • 21
  • Use `FocusManager.FocusedElement` like @pushpraj suggested and remove your attached property... why even set it if you don't want to use it? I don't see any reason for using a `UserControl` here either... you could do all that with simple `Style`s and `DataTemplate`s. Please see the[ Control Authoring Overview‎](http://msdn.microsoft.com/en-us/library/ms745025(v=vs.110).aspx#models_for_control_authoring) page on MSDN to see when it *is* appropriate to derive a class from `UserControl`. – Sheridan Jun 05 '14 at 08:55
  • Thanks, Sheridan, for your feedback. The reason I am using UserControl is because I am trying to add a section to the form that can dynamically create more text boxes using a certain logic in the viewModel. The code I presented here is a stripped down version of my actual application. I was trying to make this using only styles but couldn't figure out, so I found in StackOverflow a solution with UserControls. The reason I have an attached property is that when a new text box is dynamically created (by clicking the button in the control) I want that box to get the focus. – user2921009 Jun 05 '14 at 19:05

2 Answers2

0

Here you go

add FocusManager.FocusedElement="{Binding ElementName=firstName}" to your stack panel

<StackPanel Orientation="Horizontal" 
            FocusManager.FocusedElement="{Binding ElementName=firstName}"/>
    <TextBox x:Name="firstName" />
    <TextBox x:Name="lastName" />
    <local:DynamicFormUserControl
        x:Name="phones"
        DataContext="{Binding PhonesViewModel}" />
    <local:DynamicFormUserControl
        x:Name="emails"
        DataContext="{Binding EmailsViewModel}" />
    <TextBox x:Name="address" />
</StackPanel>

also notice that you may need to prevent items control in the user control from focusing itself

<ItemsControl x:Name="items" Focusable="False" >
    <ItemsControl.ItemTemplate>
pushpraj
  • 13,458
  • 3
  • 33
  • 50
  • Thank you for the answer, but it just doesn't work. I've tried to do that already but the application keeps putting the focus on the first textbox of the phones UserControl instead of the first textBox of the entier form as soon as the form is created. In my real application I actually used a grid instead of a StackPanel, does the focus change when I use a different type of panel? – user2921009 Jun 05 '14 at 19:12
  • are you setting `IsFocused` property somewhere before you expect focus? for me I copied your code and add `FocusManager.FocusedElement` and it worked for me. I didn't set IsFocused anywhere in my code. perhaps the code you've mentioned is inside some other focusable container which is not focused. – pushpraj Jun 06 '14 at 00:56
  • Yeah, I figured out what the problem was. My mistake was that I didn't explain right from the start that the whole form I built is itself a UserControl inside a window, and for a reason I don't really understand UserControl just doesn't get focus even if you set the Focus() or the FocusedElement. I wrote an answer to this post with explanation of how I managed to solve the problem. If you think you have a simpler solution I would appreciate to hear, since the solution I found adds some lines in the code-behind. Thanks again for your help, though. – user2921009 Jun 06 '14 at 06:04
0

I guess I managed to find a solution. The problem was that the form I created was itself a user control inside a window, and never got focus. I didn't think that would be relevant so I didn't mention it in my previous post- sorry. I found in this solution for forcing focus to a user control.

Basically, when I have a UserControl inside a window it doesn't get focus even if I try to set the focus with either Focus() or FocusedElement. So to overcome this problem I found on a different post a workaround. Basically I added it to the code-behind of the UserControl that contains the firstName TextBox. If we call the UserControl, say, PersonalInfoUserControl, the constructor of the control would look like this:

public PersonalInfoUserControl()
{
    InitializeComponent();
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(UserControl_IsVisibleChanged); 
}

I added an event handler to the IsVisibleChanged event of the control. The method would look like this:

void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
        Dispatcher.BeginInvoke(
    DispatcherPriority.ContextIdle,
    new Action(delegate()
    {
    firstName.Focus();
    }));
} 
}  
Community
  • 1
  • 1
user2921009
  • 711
  • 1
  • 10
  • 21
  • Could you add the code changes from you original post. The link could break and what you've explained, in words, what the fix was, it may not be obvious for everyone. – ChiefTwoPencils Jun 06 '14 at 01:03