static Popup()
{
EventManager.RegisterClassHandler(typeof(Popup), Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture));
// 忽略其他代码
}
private static void OnLostMouseCapture(object sender, MouseEventArgs e)
{
Popup popup = sender as Popup;
if (!popup.StaysOpen)
{
PopupRoot root = popup._popupRoot.Value;
// Reestablish capture if an element within us lost capture
// (hence we receive the LostCapture routed event) and capture
// is not being acquired anywhere else.
//
// Note we do not reestablish capture if we are losing capture
// ourselves.
bool reestablishCapture = e.OriginalSource != root && Mouse.Captured == null && MS.Win32.SafeNativeMethods.GetCapture() == IntPtr.Zero;
if(reestablishCapture)
{
popup.EstablishPopupCapture();
e.Handled = true;
}
else
{
// 忽略其他代码
}
}
}
private void EstablishPopupCapture(bool isRestoringCapture=false)
{
if (!_cacheValid[(int)CacheBits.CaptureEngaged] && (_popupRoot.Value != null) &&
(!StaysOpen))
{
IInputElement capturedElement = Mouse.Captured;
PopupRoot parentPopupRoot = capturedElement as PopupRoot;
if (parentPopupRoot != null)
{
if (isRestoringCapture)
{
// if the other PopupRoot is restoring capture back to this
// popup, ignore mouse button events until both buttons have been
// released. Otherwise a mouse click outside a chain of
// "nested" popups would dismiss two of them - one on MouseDown
// and another on MouseUp.
if (Mouse.LeftButton != MouseButtonState.Released ||
Mouse.RightButton != MouseButtonState.Released)
{
_cacheValid[(int)CacheBits.IsIgnoringMouseEvents] = true;
}
}
else
{
// this is a "nested" popup, invoked while another popup is open.
// We need to restore capture to the previous popup root when
// we're done
ParentPopupRootField.SetValue(this, parentPopupRoot);
}
// in either case, taking capture away from the other PopupRoot is OK.
capturedElement = null;
}
if (capturedElement == null)
{
// When the mouse is not already captured, we will consider the following:
// In all cases but Modeless, we want the popup and subtree to receive
// mouse events and prevent other elements from receiving those messages.
Mouse.Capture(_popupRoot.Value, CaptureMode.SubTree);
_cacheValid[(int)CacheBits.CaptureEngaged] = true;
}
}
}