将焦点转移到wpf中控件的子部分(在其模板中)

时间:2011-03-01 09:02:31

标签: wpf xaml focus controltemplate

我有一个textBox需要在某些情况下“转换”为DatePicker。

使用模板轻松完成:

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="local:MyTextBox.IsDate" Value="True">
                <Setter Property="Template" Value="{StaticResource DateTextBoxTemplate}" />
            </Trigger>
        </Style.Triggers>
    </Style>
</TextBox.Style>

然后:

<ControlTemplate x:Key="DateTextBoxTemplate" TargetType="TextBox">
    <DatePicker x:Name="DateContent"
                Text="{Binding RelativeSource={RelativeSource AncestorType=TextBox}, Path=Text, Mode=TwoWay}" />
</ControlTemplate>
问题是:当我点击它时,焦点不会“转移”到日期选择器上。

即:如果我点击控件,则datePicker不会获得焦点。为了实现这一点,我必须再次点击它。

我知道我可以在我的代码背后做:

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);

    if (IsDate)
    {
        DatePicker dateContent = Template.FindName("DateContent", this) as DatePicker;
        if (dateContent != null) dateContent.Focus();
    }
}

但这并不能让我满意,因为我很确定有一种方法可以在xaml中完成所有操作而我只是不知道它。

我发现了另一个提及FocusManager.FocusedElement="{Binding ElementName=DateContent}"选项的问题,但我不知道我可以把这段代码放在哪里:它不能添加到controlTemplate(我怀疑),如果我把它在封装模板中的datePicker的网格上,基本没用。

所以我只能在xaml中这样做吗?如果是,怎么样?

2 个答案:

答案 0 :(得分:5)

我过去曾经使用过它,但它已经有效了

<ControlTemplate x:Key="DateTextBoxTemplate" TargetType="TextBox">
    <DatePicker x:Name="DateContent" Text="{Binding RelativeSource={RelativeSource AncestorType=TextBox}, Path=Text, Mode=TwoWay}"/>
    <ControlTemplate.Triggers>
        <Trigger Property="IsFocused" Value="True">
            <Setter TargetName="DateContent"
                    Property="FocusManager.FocusedElement"
                    Value="{Binding ElementName=DateContent}" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

答案 1 :(得分:2)

您可以通过告诉DatePicker在加载时默认应该关注它来实现所需的行为。为此,您可以创建Attached Behavior,如下所示:

public static class FocusExtensions
{
    public static bool GetIsDefaultFocusElement(DependencyObject obj) 
    {
        return (bool)obj.GetValue(IsDefaultFocusElementProperty);
    }

    public static void SetIsDefaultFocusElement(DependencyObject obj, bool value) 
    {
        obj.SetValue(IsDefaultFocusElementProperty, value);
    }

    public static readonly DependencyProperty IsDefaultFocusElementProperty =
        DependencyProperty.RegisterAttached("IsDefaultFocusElement", typeof(bool), typeof(FocusExtensions), new UIPropertyMetadata(false, OnIsDefaultFocusElementChanged));

    private static void OnIsDefaultFocusElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    {
        var fe = (FrameworkElement)d;

        if (!(bool)e.NewValue) 
        {
            return;
        }

        if (fe.IsLoaded) 
        {
            SetFocus(fe);
        }
        else 
        {
            fe.Loaded += OnDefaultFocusElementLoaded;
        }
    }

    private static void OnDefaultFocusElementLoaded(object sender, RoutedEventArgs e) 
    {
        var fe = (FrameworkElement) sender;

        fe.Loaded -= OnDefaultFocusElementLoaded;

        SetFocus(fe);
    }

    private static void SetFocus(FrameworkElement element) 
    {
        element.Focus();
    }
}

然后,您可以在IsDefaultFocusElement上设置DatePicker附加属性,每次加载DatePicker时,它都会获得焦点:

<ControlTemplate x:Key="DateTextBoxTemplate" TargetType="TextBox">
    <DatePicker x:Name="DateContent"
                Text="{Binding RelativeSource={RelativeSource AncestorType=TextBox}, Path=Text, Mode=TwoWay}"
                my:FocusExtensions.IsDefaultFocusElement="True" />
</ControlTemplate>

此行为可用于应用程序中您需要指定默认情况下必须聚焦的元素的任何其他位置(例如,当您打开对话框并希望第一个字段立即聚焦时)。 / p>