在鼠标中注册的eventandler.addpreviewmousedownouterecapturedelementh

本文关键字:eventandler addpreviewmousedownouterecapturedelementh 注册 鼠标 | 更新日期: 2023-09-27 18:05:44

所以我试图建立一个下拉颜色选择器自定义控件。我目前有它的设置,所以当我点击矩形部分的弹出部分打开。我想有它,所以当我点击控制外的任何地方弹出关闭。我写了一个MouseButtonEventHandler,注册到Mouse.AddPreviewMouseDownOutsideCapturedElementHandler。但是,无论我在窗口的哪个位置单击,处理程序都不会命中。我觉得这很奇怪,因为WPF工具包中有两个控件使用了这种方法。这两个是DropDownButton Control和CalculatorUpDown Control。我有没有漏掉什么能阻止操控者开火的东西?

控制代码:

[TemplatePart(Name = DisplayColorPart, Type = typeof(Rectangle))]
[TemplatePart(Name = DropDownPart, Type = typeof(Popup))]
public class ColorPickerDropDown : Control
{
    private const string DisplayColorPart = "PART_DisplayColor";
    private const string DropDownPart = "PART_DropDown";

    private Rectangle _displayColorElement;
    private Popup _dropDownElement;

    public Rectangle DisplayColorElement
    {
        get { return _displayColorElement; }
        set
        {
            _displayColorElement = value;
            InitalizeDisplayColorElement();
        }
    }
    public Popup DropDownElement
    {
        get { return _dropDownElement; }
        set { _dropDownElement = value; }
    }

    public static readonly DependencyProperty CurrentColorProperty =
        DependencyProperty.Register("CurrentColor", typeof(Brush), typeof(ColorPickerDropDown),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public Brush CurrentColor
    {
        get { return (Brush)GetValue(CurrentColorProperty); }
        set { SetValue(CurrentColorProperty, value); }
    }

    static ColorPickerDropDown()
    {
        DefaultStyleKeyProperty
            .OverrideMetadata(typeof (ColorPickerDropDown),
            new FrameworkPropertyMetadata(typeof (ColorPickerDropDown)));
    }
    public ColorPickerDropDown()
    {
        Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OutsideControlClick);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        if (DisplayColorElement == null) DisplayColorElement = GetTemplateChild(DisplayColorPart) as Rectangle;
        if (DropDownElement == null) DropDownElement = GetTemplateChild(DropDownPart) as Popup;
    }

    private void InitalizeDisplayColorElement()
    {
        if (DisplayColorElement == null) return;
        DisplayColorElement.AddHandler(Rectangle.MouseLeftButtonDownEvent,
                                       new RoutedEventHandler(DisplayColorClick),
                                       handledEventsToo: true);
    }
    private void DisplayColorClick(object sender, RoutedEventArgs e)
    {
        DropDownElement.IsOpen = DropDownElement.IsOpen ? false : true;
    }
    public void OutsideControlClick(object sender, MouseButtonEventArgs e)
    {
        if (!DropDownElement.IsMouseOver && !DisplayColorElement.IsMouseOver)
        {
            DropDownElement.IsOpen = false;
        }
    }
}
控制风格:

<Style TargetType="{x:Type local:ColorPickerDropDown}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ColorPickerDropDown}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <StackPanel Background="Transparent">
                        <Rectangle Name="PART_DisplayColor"
                                   Height="{TemplateBinding Height}"
                                   Width="{TemplateBinding Width}"
                                   Fill="{Binding CurrentColor, RelativeSource={RelativeSource TemplatedParent}}"/>
                        <Popup Name="PART_DropDown"
                               PlacementTarget="{Binding ElementName=PART_DisplayColor}"
                               Width="{Binding ElementName=PART_DisplayColor}"
                               StaysOpen="True"
                               AllowsTransparency="True">
                            <Border Background="DodgerBlue"
                                    BorderThickness="1"
                                    BorderBrush="AliceBlue"
                                    CornerRadius="0,0,0,15">
                                <StackPanel>
                                    <Rectangle Height="100"
                                               Width="98"/>
                                </StackPanel>
                            </Border>
                        </Popup>
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

在鼠标中注册的eventandler.addpreviewmousedownouterecapturedelementh

PreviewMouseDownOutsideCapturedElement附加事件仅在使用Mouse.Capture()方法启用鼠标捕获时才有效。因此,您需要在打开弹出窗口后立即开始鼠标捕获。当鼠标捕获是活跃的,IsMouseOver不幸不能再使用;你必须直接检查鼠标坐标(参见下面示例中的IsWithin方法)。

我已经修改了你的代码如下(见***标记的地方),它为我工作:

[TemplatePart(Name = DisplayColorPart, Type = typeof(Rectangle))]
[TemplatePart(Name = DropDownPart, Type = typeof(Popup))]
public class ColorPickerDropDown : Control
{
    private const string DisplayColorPart = "PART_DisplayColor";
    private const string DropDownPart = "PART_DropDown";
    private Rectangle _displayColorElement;
    private Popup _dropDownElement;
    public Rectangle DisplayColorElement
    {
        get { return _displayColorElement; }
        set
        {
            _displayColorElement = value;
            InitalizeDisplayColorElement();
        }
    }
    public Popup DropDownElement
    {
        get { return _dropDownElement; }
        set { _dropDownElement = value; }
    }
    public static readonly DependencyProperty CurrentColorProperty =
        DependencyProperty.Register("CurrentColor", typeof(Brush), typeof(ColorPickerDropDown),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public Brush CurrentColor
    {
        get { return (Brush)GetValue(CurrentColorProperty); }
        set { SetValue(CurrentColorProperty, value); }
    }
    static ColorPickerDropDown()
    {
        DefaultStyleKeyProperty
            .OverrideMetadata(typeof(ColorPickerDropDown),
            new FrameworkPropertyMetadata(typeof(ColorPickerDropDown)));
    }
    public ColorPickerDropDown()
    {
        Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OutsideControlClick);
    }
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        if (DisplayColorElement == null) DisplayColorElement = GetTemplateChild(DisplayColorPart) as Rectangle;
        if (DropDownElement == null) DropDownElement = GetTemplateChild(DropDownPart) as Popup;
    }
    private void InitalizeDisplayColorElement()
    {
        if (DisplayColorElement == null) return;
        DisplayColorElement.AddHandler(Rectangle.MouseLeftButtonDownEvent,
                                       new RoutedEventHandler(DisplayColorClick),
                                       handledEventsToo: true);
    }
    private void DisplayColorClick(object sender, RoutedEventArgs e)
    {
        DropDownElement.IsOpen = DropDownElement.IsOpen ? false : true;
        if (DropDownElement.IsOpen) // ***
        {                           // ***
            Mouse.Capture(this);    // ***
        }                           // ***
    }
    public void OutsideControlClick(object sender, MouseButtonEventArgs e)
    {
        if (!IsWithin(DropDownElement.Child, e) && !IsWithin(DisplayColorElement, e)) // ***
        {
            DropDownElement.IsOpen = false;
            Mouse.Capture(null); // ***
        }
    }
    // *** Is mouse within the bounds of the UI element?
    public static bool IsWithin(UIElement element, MouseButtonEventArgs e)
    {
        FrameworkElement elem = element as FrameworkElement;
        return (elem == null) ? false :
            new Rect(0, 0, elem.ActualWidth, elem.ActualHeight).Contains(e.GetPosition(element));
    }
}

还请注意,在您的XAML中有一个小错别字。行

Width="{Binding ElementName=PART_DisplayColor}"
应该

Width="{Binding ElementName=PART_DisplayColor, Path=ActualWidth}"