перенести фокус на вложенную часть элемента управления (в его шаблоне) в wpf - PullRequest
1 голос
/ 01 марта 2011

У меня есть текстовое поле, которое при определенных обстоятельствах необходимо «преобразовать» в 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>

проблема в том, что при щелчке по нему фокус не «переносится» на средство выбора даты.

, т. Е. Если я нажимаю на элемент управления, средство выбора даты не получает фокус.Я должен щелкнуть по нему еще раз, чтобы это произошло.

Я знаю, что могу сделать в своем коде:

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 ]

5 голосов
/ 01 марта 2011

Я использовал это в прошлом, и это сработало

<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>
2 голосов
/ 01 марта 2011

Вы можете добиться желаемого поведения, сказав DatePicker, что оно должно быть сфокусировано по умолчанию при загрузке.Для этого вы можете создать присоединенное поведение следующим образом:

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>

Это поведение можно использовать в любых других местах вашего приложения, где вам нужно указать элемент, который должен быть сфокусирован по умолчанию (например, когда вы открываете диалоговое окно ихочу, чтобы первое поле было сразу сфокусировано).

...