Setting Focus on a Control Within a ControlTemplate (Part 2)

Chris Ward picture Chris Ward · Dec 1, 2010 · Viewed 7.7k times · Source

I'm stumped on what must surely be one of the most common WPF requirements. I've read this question but my implementation of the solution does not work.

Here's the markup for the lookless control:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfTest">
  <Style TargetType="{x:Type local:CustomControl}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:CustomControl}">
          <Border>
            <TextBox x:Name="myTextBox" />
          </Border>
          <ControlTemplate.Triggers>
            <Trigger Property="IsFocused"
                     Value="True">
              <Setter Property="FocusManager.FocusedElement"
                      Value="{Binding ElementName=myTextBox}" />
              <Setter TargetName="myTextBox"
                      Property="Background"
                      Value="Green" />
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

Here's the markup for the Window that contains an instance of the CustomControl:

<Window x:Class="WpfTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTest"
        Title="Window1" Height="300" Width="300">

  <local:CustomControl x:Name="CCtl" />
</Window>

And here's the code-behind:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Loaded += (RoutedEventHandler)delegate { CCtl.Focus(); };
    }
}

When Window1 is loaded, the text box turns green (indicating that the trigger works) but focus remains with CCtl and not the text box. Doubtless this has to do with the output displaying the following data error:

Cannot find source for binding with reference 'ElementName=myTextBox'. BindingExpression:(no path); DataItem=null; target element is 'CustomControl' (Name='CCtl'); target property is 'FocusedElement' (type 'IInputElement').

I've no idea why this error is appearing. Any pointers gratefully received, thanks.

Answer

John Bowen picture John Bowen · Dec 1, 2010

Try using this for your Trigger instead:

<Trigger Property="IsFocused" Value="True">
    <Setter TargetName="myTextBox" Property="FocusManager.FocusedElement" Value="{Binding ElementName=myTextBox}" />
</Trigger>

The error is telling you that it can't locate myTextBox because the name isn't in scope where the FocusedElement property is being applied. In this case that's on the CCtl instance itself, which can't see inside its own template. By setting the property on something inside the template the Binding can locate the named element.