1
votes

I am making a numeric text box, which can also contain various additional symbols to denote if the data contained in the control is a percentile, radius, etc. For this I have a grid with a text box to the left and a TextBlock to the right. Here is a picture:

enter image description here

The problem that I am having with this, however, is that if the mouse is over the textblock, and I click, I cannot get the TextBox to gain focus. I have tried _textbox.Focus() on mouse down of the textblock, as well as on the parent grid. This did not work.

After some googling, I read that I could put FocusManager.FocusedElement="{Binding ElementName=_textbox}" on the parent Grid, and this would solve my problem. However, even with this, the Textbox still does not gain focus. I've even tried making neither the textbox or textblock hit-testable, and instead use the grid itself as a hit test, but even with this, the textbox itself still will not gain focus. I'm at a loss of what to do here. Does anyone know how I can make the textbox gain focus, when either the parent grid is clicked, or the textblock is clicked? Or Both?

Here is my XAML:

<UserControl
    x:Class="VoidwalkerEngine.Editor.Controls.NumericTextBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Height="32"
    d:DesignWidth="80"
    BorderThickness="0"
    mc:Ignorable="d">
    <UserControl.Resources>
        <Style x:Key="ButtonTop" TargetType="Button">
            <Setter Property="Background" Value="White" />
            <Setter Property="TextBlock.TextAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border
                            x:Name="ButtonBackground"
                            Background="{DynamicResource Voidwalker_Gradient_Button}"
                            BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
                            BorderThickness="1,0,0,1"
                            CornerRadius="0,2,0,0">
                            <ContentPresenter
                                x:Name="contentPresenter"
                                Margin="{TemplateBinding Padding}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                Content="{TemplateBinding Content}"
                                ContentTemplate="{TemplateBinding ContentTemplate}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource Voidwalker_Gradient_ButtonPressed}" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource VoidwalkerButtonBrush}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ButtonBottom" TargetType="Button">
            <Setter Property="Background" Value="White" />
            <Setter Property="TextBlock.TextAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border
                            x:Name="ButtonBackground"
                            Background="{DynamicResource Voidwalker_Gradient_Button}"
                            BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
                            BorderThickness="1,1,0,0"
                            CornerRadius="0,0,2,0">
                            <ContentPresenter
                                x:Name="contentPresenter"
                                Margin="{TemplateBinding Padding}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                Content="{TemplateBinding Content}"
                                ContentTemplate="{TemplateBinding ContentTemplate}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource Voidwalker_Gradient_ButtonPressed}" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource VoidwalkerButtonBrush}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Border
        Background="{DynamicResource Voidwalker_Brush_ContextArea}"
        BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
        BorderThickness="1"
        CornerRadius="3">
        <Grid Focusable="False">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="23" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Border
                Grid.Row="0"
                Grid.RowSpan="2"
                Grid.Column="0"
                BorderThickness="0"
                CornerRadius="2,0,0,2">
                <Grid
                    Cursor="IBeam"
                    FocusManager.FocusedElement="{Binding ElementName=_textbox}"
                    MouseDown="_backAreaGrid_OnClick">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50*" />
                        <ColumnDefinition Width="50*" />
                    </Grid.ColumnDefinitions>
                    <TextBox
                        x:Name="_textbox"
                        Grid.Column="0"
                        Margin="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Center"
                        VerticalContentAlignment="Center"
                        Background="{DynamicResource VoidwalkerContextBrush}"
                        BorderThickness="0"
                        CommandManager.PreviewExecuted="_numericDisplayTextBox_OnPreviewExecuted"
                        Foreground="{DynamicResource Voidwalker_Brush_ActiveTextForeground}"
                        GotFocus="_textbox_OnGotFocus"
                        LostFocus="_numericDisplayTextBox_OnLostFocus"
                        MouseDoubleClick="_textbox_OnMouseDoubleClick"
                        PreviewKeyDown="_numericDisplayTextBox_OnPreviewKeyDown"
                        PreviewMouseWheel="_numericDisplayTextBox_OnPreviewMouseWheel"
                        Text="0"
                        TextAlignment="Right"
                        TextChanged="_numericDisplayTextBox_OnTextChanged" />
                    <TextBlock
                        x:Name="OperatorDisplayTextBox"
                        Grid.Column="1"
                        VerticalAlignment="Center"
                        Cursor="IBeam"
                        Foreground="{DynamicResource Voidwalker_Brush_ActiveTextForeground}"
                        Text="%" />
                </Grid>

            </Border>

            <Button
                Grid.Row="0"
                Grid.Column="1"
                BorderThickness="1,0,0,0"
                Click="Increment_Button_OnClick"
                Style="{DynamicResource ButtonTop}">
                <Path Data="M 1,4.5  L 4.5,1  L 8,4.5" Fill="{DynamicResource Voidwalker_Brush_ActiveTextForeground}" />
            </Button>
            <Button
                Grid.Row="1"
                Grid.Column="1"
                BorderThickness="1,0,0,0"
                Click="Decrement_Button_OnClick"
                Style="{DynamicResource ButtonBottom}">
                <Path
                    ClipToBounds="True"
                    Data="M 1,1.5 L 4.5,5 L 8,1.5"
                    Fill="{DynamicResource Voidwalker_Brush_ActiveTextForeground}" />
            </Button>
        </Grid>
    </Border>
</UserControl>
1
Also, I've completely wiped out the code-behind, in fruitless attempts to solve this dilemma, so I'm certain this problem is not due to any of that.Krythic
It should be noted that I originally tried having just a text box that accepted only numbers and the additional symbols, but this was truly a clusterf**k. It worked, but I wanted to do it a different way, which is what I'm showing to you now.Krythic

1 Answers

0
votes

I figured it out after reading this page. I don't know why this code works...like, at all actually. It seems like i'm using a backwards, roundabout way into the control to avoid threading issues... isn't that what the Dispatcher is for? So is it safe to assume that a .Focus() method does nothing unless it's used like below? It's whatever, I guess, less hair pulling now, and more coding. Here is the code that worked for me. All I had to do was add this to the parent grid's MouseDown event:

        private void _backAreaGrid_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            Dispatcher.BeginInvoke(
                DispatcherPriority.ContextIdle,
                new Action(delegate
                {
                    _textbox.Focus();
                }));
        }

The textbox gains focus regardless of what I click on in the surrounding grid.