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

发布于 2024-10-20 06:01:03 字数 1431 浏览 2 评论 0原文

我有一个文本框,在某些情况下需要“转换”为 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 中执行此操作吗?如果是,怎么办?

I have a textBox that needs to be "transformed" into a DatePicker under certain circumstances.

easily done with template:

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

and then:

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

the trouble is: the focus is not "transferred" to the datepicker when I click on it.

i.e: if I click on the control, the datePicker does not get the focus. I have to click on it once again for this to happen.

I know I can do in my code behind:

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

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

but this does not really satisfy me as I'm pretty sure there is a way to do it all in xaml and I just don't know about it.

I found an other question mentioning the FocusManager.FocusedElement="{Binding ElementName=DateContent}" option, but I have no clue as to where I could put this piece of code: it cannot be added to the controlTemplate (as I suspected), and if I put it on a grid encapsulating the datePicker in the template, it is basically useless.

so can I do this in xaml only? and if yes, how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

余生一个溪 2024-10-27 06:01:03

我过去用过这个并且很有效

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

I've used this in the past and it has worked

<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>
許願樹丅啲祈禱 2024-10-27 06:01:03

您可以通过告诉 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>

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

You can achieve the desired behavior by telling the DatePicker that it should be focused by default when loaded. To do this you can create an Attached Behavior like this:

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

Then you can set the IsDefaultFocusElement attached property on the DatePicker and every time the DatePicker is loaded it will receive focus:

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

This behavior can be used in any other places in your application where you need to specify an element that has to be focused by default (e.g. when you open a dialog and you want the first field to be focused right away).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文