在鼠标中注册的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>
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}"