none
Why the TextBox always can not be focus? RRS feed

  • Question

  • I want to create a `CustomControl` which can be multi-select in a `Grid` and edit the content while DoubleClick it.

    I wrote the CustomControl like this
    Here is the XAML:
    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp1">


        <Style TargetType="{x:Type local:CustomControl1}">
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Height" Value="18"/>
            <Setter Property="Width" Value="80"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <Grid FocusManager.FocusedElement="{Binding ElementName=textBox}" x:Name="G">
                                <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" TextBlock.FontFamily="{TemplateBinding FontFamily}" TextBlock.FontSize="{TemplateBinding FontSize}" TextBlock.FontWeight="{TemplateBinding FontWeight}"/>
                                <TextBox x:Name="textBox" Background="White" Focusable="True" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontWeight="{TemplateBinding FontWeight}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="Collapsed" Text="{Binding ElementName=contentPresenter,Path=Content,Mode=TwoWay}"></TextBox>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter TargetName="G" Property="Background" Value="Red"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="contentPresenter" Property="Visibility" Value="Collapsed"></Setter>
                                <Setter TargetName="textBox" Property="Visibility" Value="Visible"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>


    Here is Code-behind:

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Data;
        using System.Windows.Documents;
        using System.Windows.Input;
        using System.Windows.Media;
        using System.Windows.Media.Imaging;
        using System.Windows.Navigation;
        using System.Windows.Shapes;

        namespace WpfApp1
        {        
            public class CustomControl1 : CheckBox
            {
                static CustomControl1()
                {
                    DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));            
                }
                public override void OnApplyTemplate()
                {
                    base.OnApplyTemplate();
                    this.MouseEnter += CustomControl1_MouseEnter;
                    this.GotMouseCapture += CustomControl1_GotMouseCapture;
                    this.MouseDoubleClick += CustomControl1_MouseDoubleClick;
                    this.LostFocus += CustomControl1_LostFocus;
                }

                private void CustomControl1_LostFocus(object sender, RoutedEventArgs e)
                {
                    this.IsSelected = false;
                }

                private void CustomControl1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
                {
                    this.IsSelected = true;
                    TextBox TB = FindVisualChildren<TextBox>(sender as DependencyObject).First();
                    TB.Focus();
                    TB.SelectAll();
                }

                private void CustomControl1_GotMouseCapture(object sender, MouseEventArgs e)
                {
                    if (e.LeftButton == MouseButtonState.Pressed)
                    {                
                        var checkbox = sender as CheckBox;
                        if (checkbox != null)
                        {
                            checkbox.IsChecked = !checkbox.IsChecked;
                            checkbox.ReleaseMouseCapture();
                        }
                    }
                }

                public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
                {
                    if (depObj != null)
                    {
                        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                        {
                            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                            if (child != null && child is T)
                            {
                                yield return (T)child;
                            }

                            foreach (T childOfChild in FindVisualChildren<T>(child))
                            {
                                yield return childOfChild;
                            }
                        }
                    }
                }

                private void CustomControl1_MouseEnter(object sender, MouseEventArgs e)
                {
                    var checkbox = sender as CheckBox;

                    if (e.LeftButton == MouseButtonState.Pressed)
                    {
                        if (checkbox != null)
                        {
                            checkbox.IsChecked = !checkbox.IsChecked;
                        }
                    }
                }

                public Boolean IsSelected
                {
                    get { return (Boolean)GetValue(IsSelectedProperty); }
                    set { SetValue(IsSelectedProperty, value); }
                }

                // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
                public static readonly DependencyProperty IsSelectedProperty =
                    DependencyProperty.Register("IsSelected", typeof(Boolean), typeof(CustomControl1), null);


            }
        }

    Finally, here is the XAML of the Window:

        <Window x:Class="WpfApp1.MainWindow"
                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"
                xmlns:local="clr-namespace:WpfApp1"
                mc:Ignorable="d"
                Title="MainWindow" Height="450" Width="800">
            <Window.Resources>



            </Window.Resources>
            <Grid x:Name="G">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="auto"></ColumnDefinition>
                    <ColumnDefinition Width="auto"></ColumnDefinition>
                    <ColumnDefinition Width="auto"></ColumnDefinition>
                    <ColumnDefinition Width="auto"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <local:CustomControl1 Grid.Column="0"></local:CustomControl1>
                <local:CustomControl1 Grid.Column="1" IsChecked="True"></local:CustomControl1>
                <local:CustomControl1 Grid.Column="2" IsChecked="True"></local:CustomControl1>
                <local:CustomControl1 Grid.Column="3"></local:CustomControl1>
            </Grid>
        </Window>

    I found that now the `TextBox` can never be visible. And soon I found that if I deleted the focus code in the `CustomControl`, the `TextBox` can be visible now. However, it cannot focus also.

        private void CustomControl1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
                {
                    this.IsSelected = true;
                    TextBox TB = FindVisualChildren<TextBox>(sender as DependencyObject).First();
                    TB.Focus();
                    TB.SelectAll();
                }


    Now the question is, how can I make the CustomControl can be visible and can focus? I don't know why it turns out to be this and how to solve it.

    I shared this sample project on Onedrive and you can edit it any time:https://1drv.ms/f/s!AtcqjirAlaGYirEioWoS7vRahHzLrQ

                                                                                      
    Monday, May 20, 2019 6:29 AM

Answers


  • What's more, I just tried add a breakpoint in CustomControl1_MouseDoubleClick and CustomControl1_LostFocus. Both of them works well but not fired.

    I don't think it is the right answer.

    Hi mywatermelon,

    Yes, I mean the CustomControl1_MouseDoubleclick is not fired, so the IsSelected property is always false, so the TextBox visibility is not visible. 

    Please see this controltemplate trigger.

    <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter TargetName="G" Property="Background" Value="Red"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="contentPresenter" Property="Visibility" Value="Collapsed"></Setter>
                                <Setter TargetName="textBox" Property="Visibility" Value="Visible"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Finally I found a very starnge way to solve this by editing the Mouse_DoubleClick to:

    TB.Visibility = Visibility.Visible;
    TB.Focus();
    TB.SelectAll();
    TB.Visibility = Visibility.Visible;

    Just by using the TB.Visibility = Visibility.Visible; twice. However, I still don't know why it can solve this also.

    • Marked as answer by mywatermelon Friday, June 7, 2019 3:34 PM
    Thursday, May 23, 2019 7:27 AM

All replies

  • Hi mywatermelon,

    In fact if you're just changing the styling, you don't need to subclass at all.You could just define a style and apply it as a generic style to checkbox.

    Or if you don't want to use the style with all checkboxes, you can give it an x:Key.

    I try your code and the CustomControl is visible, when you call the DefaultStyleKeyProperty.OverrideMetadata method in the static constructor you are telling WPF that you will define your own custom default style for the custom control in a ResourceDictionary called "generic.xaml" in a folder called “Themes” at the root of the project where the custom control class is defined.

    According to your code, I find CustomControl1_MouseDoubleClick1 and CustomControl1_LostFocus1 don't fire, so the IsSelected property is always false, so the CustomControl1  is invisible.

    Here is the same thread that you can take a look:

    https://social.msdn.microsoft.com/Forums/aspnet/en-US/86d274be-ad49-48ba-9472-dab1d8f54845/wpf-custom-controls?forum=wpf

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, May 21, 2019 6:45 AM
    Moderator
  • Hi mywatermelon,

    In fact if you're just changing the styling, you don't need to subclass at all.You could just define a style and apply it as a generic style to checkbox.

    Or if you don't want to use the style with all checkboxes, you can give it an x:Key.

    I try your code and the CustomControl is visible, when you call the DefaultStyleKeyProperty.OverrideMetadata method in the static constructor you are telling WPF that you will define your own custom default style for the custom control in a ResourceDictionary called "generic.xaml" in a folder called “Themes” at the root of the project where the custom control class is defined.

    According to your code, I find CustomControl1_MouseDoubleClick1 and CustomControl1_LostFocus1 don't fire, so the IsSelected property is always false, so the CustomControl1  is invisible.

    Here is the same thread that you can take a look:

    https://social.msdn.microsoft.com/Forums/aspnet/en-US/86d274be-ad49-48ba-9472-dab1d8f54845/wpf-custom-controls?forum=wpf

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    I think there is some wrong.

    I need to change its style for I want the checkbox looks like what I want. And the style now seems works well.

    What's more, I just tried add a breakpoint in CustomControl1_MouseDoubleClick and CustomControl1_LostFocus. Both of them works well but not fired.

    I don't think it is the right answer.

    Tuesday, May 21, 2019 7:34 AM

  • What's more, I just tried add a breakpoint in CustomControl1_MouseDoubleClick and CustomControl1_LostFocus. Both of them works well but not fired.

    I don't think it is the right answer.

    Hi mywatermelon,

    Yes, I mean the CustomControl1_MouseDoubleclick is not fired, so the IsSelected property is always false, so the TextBox visibility is not visible. 

    Please see this controltemplate trigger.

    <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter TargetName="G" Property="Background" Value="Red"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="contentPresenter" Property="Visibility" Value="Collapsed"></Setter>
                                <Setter TargetName="textBox" Property="Visibility" Value="Visible"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, May 22, 2019 8:18 AM
    Moderator

  • What's more, I just tried add a breakpoint in CustomControl1_MouseDoubleClick and CustomControl1_LostFocus. Both of them works well but not fired.

    I don't think it is the right answer.

    Hi mywatermelon,

    Yes, I mean the CustomControl1_MouseDoubleclick is not fired, so the IsSelected property is always false, so the TextBox visibility is not visible. 

    Please see this controltemplate trigger.

    <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter TargetName="G" Property="Background" Value="Red"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="contentPresenter" Property="Visibility" Value="Collapsed"></Setter>
                                <Setter TargetName="textBox" Property="Visibility" Value="Visible"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Finally I found a very starnge way to solve this by editing the Mouse_DoubleClick to:

    TB.Visibility = Visibility.Visible;
    TB.Focus();
    TB.SelectAll();
    TB.Visibility = Visibility.Visible;

    Just by using the TB.Visibility = Visibility.Visible; twice. However, I still don't know why it can solve this also.

    • Marked as answer by mywatermelon Friday, June 7, 2019 3:34 PM
    Thursday, May 23, 2019 7:27 AM
  • Hi mywatermelon, 

    I am glad to hear you have solved your issue by yourself, please remember to close your thread by marking your last reply as answer, it is beneficial to other community members who face the same issue.

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, June 5, 2019 9:34 AM
    Moderator