Daniel Ward
Daniel Ward

Reputation: 274

Why does MouseLeftButtonDown not work for the button in my custom control but PreviewMouseLeftButtonDown and AddHandler do?

I understand that if I were trying to bubble or tunnel the event to another control, the Button would sort of "steal" the event, but it is the actual Button itself I am trying to invoke the event on. There shouldn't be anything out of the ordinary in these files but just in case here are the whole things (the issue is in OnApplyTemplate in the SearchTextBox.cs):

Snippet from 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:

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 App
{
    public class SearchTextBox : TextBox
    {
        public static readonly DependencyProperty LabelTextProperty;
        public static readonly DependencyProperty LabelTextColorProperty;
        public static readonly DependencyProperty SearchModeProperty;
        public static readonly DependencyProperty HasTextProperty;
        private static readonly DependencyPropertyKey HasTextPropertyKey;
        public static readonly DependencyProperty SourceProperty;

        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));
            SearchModeProperty = DependencyProperty.Register("SearchMode", typeof(SearchMode), typeof(SearchTextBox), new PropertyMetadata(SearchMode.Instant));
            HasTextPropertyKey = DependencyProperty.RegisterReadOnly("HasText", typeof(bool), typeof(SearchTextBox), new PropertyMetadata());
            HasTextProperty = HasTextPropertyKey.DependencyProperty;
            SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(SearchTextBox));
        }

        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 SearchMode SearchMode
        {
            get { return (SearchMode)GetValue(SearchModeProperty); }
            set { SetValue(SearchModeProperty, 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 override void OnApplyTemplate()
        {
            Button b = GetTemplateChild("PART_Button") as Button;
            if (b != null)
            {
                b.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);

                // This also works
                //b.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown));

                // Doesn't work
                //b.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
            }

            base.OnApplyTemplate();
        }

        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Text = "";
        }
    }
}

Upvotes: 1

Views: 876

Answers (1)

user2250152
user2250152

Reputation: 20625

Try to read this:

http://msdn.microsoft.com/en-us/library/system.windows.uielement.mouseleftbuttondown.aspx

MouseLeftButtonDownEvent is handled by another control, very often by ButtonBase:

http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs#1001a15c43ab91f9 (Line 414)

The right way is to use AddHandler or PreviewMouseLeftButtonDown event

Upvotes: 2

Related Questions