为什么我必须在按钮点击事件后调用Focus()才能实现无缝行为?

时间:2014-05-20 15:51:21

标签: wpf xaml event-handling

我有一个SearchTextBox自定义控件,如图所示:

SearchTextBox

当鼠标点击它时,该标签消失。如果用户单击并且没有文本,则标签会重新出现(如果用户单击但是在那里留下文本,则文本保留并且标签保持隐藏状态)。当用户开始输入时,此按钮将替换图像:

SearchTextBox2

当用户点击该按钮时,文本将被清除。

这一切都正常。我所说的奇怪的行为是,当点击清除按钮时,标签在控制器上闪烁一瞬间才消失(它应该在整个时间内保持隐藏状态)。由于XAML中的Multitrigger使用IsFocused,我想也许我可以通过在Focus()事件完成之前在代码隐藏中调用Click来解决问题。这似乎有点hacky,但它确实有效。我的问题是,为什么我必须这样做才能让它发挥作用"对吧?"

Generic.xaml的片段:

<SolidColorBrush x:Key="TextBoxBorder" Color="#ababab"/>
    <Style TargetType="{x:Type ui:SearchTextBox}">
        <Setter Property="AllowDrop" Value="True" />
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
        <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="LabelText" Value="Search for..." />
        <Setter Property="LabelTextColor" Value="Gray" />
        <Setter Property="Padding" Value="1" />
        <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
        <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ui:SearchTextBox}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualHeight}" />
                            </Grid.ColumnDefinitions>

                            <Label x:Name="LabelText"
                                   Grid.Column="0"
                                   Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LabelTextColor}"
                                   Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LabelText}"
                                   Padding="0"
                                   Margin="5,0,0,0"
                                   FontStyle="Italic"
                                   VerticalAlignment="Center"
                                   Visibility="Hidden" />
                            <ScrollViewer Grid.Column="0" Panel.ZIndex="1" x:Name="PART_ContentHost" Background="{TemplateBinding Background}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Margin="5,0,0,0" Padding="0"/>
                            <Image x:Name="Image" Grid.Column="1" Visibility="Hidden" Source="search2.png" Width="15" Height="15" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
                            <Button x:Name="PART_Button" Grid.Column="1" Width="15" Height="15">
                                <Border HorizontalAlignment="Center" VerticalAlignment="Center">
                                    <Image Source="searchstop.png" />
                                </Border>
                            </Button>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Text" Value="">
                            <Setter TargetName="Image" Property="Visibility" Value="Visible" />
                            <Setter TargetName="PART_Button" Property="Visibility" Value="Hidden" />
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Text" Value="" />
                                <Condition Property="IsFocused" Value="False" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="LabelText" Property="Visibility" Value="Visible" />
                            <Setter TargetName="PART_ContentHost" Property="Visibility" Value="Hidden" />
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

SearchTextBox.cs:

    public class SearchTextBox : TextBox
    {
        public static readonly DependencyProperty LabelTextProperty;
        public static readonly DependencyProperty LabelTextColorProperty;
        public static readonly DependencyProperty HasTextProperty;
        private static readonly DependencyPropertyKey HasTextPropertyKey;
        public static readonly DependencyProperty SourceProperty;
        private static readonly DependencyProperty IsMouseLeftButtonDownProperty;

        static SearchTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchTextBox), new FrameworkPropertyMetadata(typeof(SearchTextBox)));

            LabelTextProperty = DependencyProperty.Register("LabelText", typeof(string), typeof(SearchTextBox));
            LabelTextColorProperty = DependencyProperty.Register("LabelTextColor", typeof(Brush), typeof(SearchTextBox));
            HasTextPropertyKey = DependencyProperty.RegisterReadOnly("HasText", typeof(bool), typeof(SearchTextBox), new PropertyMetadata());
            HasTextProperty = HasTextPropertyKey.DependencyProperty;
            SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(SearchTextBox));
            IsMouseLeftButtonDownProperty = DependencyProperty.Register("IsMouseLeftButtonDown", typeof(bool), typeof(SearchTextBox), new PropertyMetadata());
        }

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);
            HasText = Text.Length != 0;
        }

        public string LabelText
        {
            get { return (string)GetValue(LabelTextProperty); }
            set { SetValue(LabelTextProperty, value); }
        }

        public Brush LabelTextColor
        {
            get { return (Brush)GetValue(LabelTextColorProperty); }
            set { SetValue(LabelTextColorProperty, value); }
        }

        public ImageSource Source
        {
            get { return (ImageSource)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public bool HasText
        {
            get { return (bool)GetValue(HasTextProperty); }
            private set { SetValue(HasTextPropertyKey, value); }
        }

        public bool IsMouseLeftButtonDown
        {
            get { return (bool)GetValue(IsMouseLeftButtonDownProperty); }
            private set { SetValue(IsMouseLeftButtonDownProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            Button b = GetTemplateChild("PART_Button") as Button;
            if (b != null)
            {
                b.Click += OnClick;
            }

            base.OnApplyTemplate();
        }

        private void OnClick(object sender, RoutedEventArgs e)
        {
            Text = "";
            Focus();
            e.Handled = true;
        }
    }

1 个答案:

答案 0 :(得分:1)

闪烁最有可能发生,因为如果您按下它,焦点会从您的控件移动到清除按钮。 您可以解决这个问题,即使清除按钮不可聚焦,即

<Button x:Name="PART_Button" Focusable="False" ... />

然后按下按钮时焦点不会移动。