当我的弹出窗口打开时,首次单击最小化或最大化或关闭按钮不起作用。 首先点击这些标题栏按钮关闭弹出菜单并移动焦点, 然后在第二次单击时窗口的最小化/最大化/关闭工作。
有没有办法 - 我们可以在第一次点击时激活这些标题栏按钮?
MainWindow.xaml
<Button Height="54" Width="50" Margin="100,0,0,0" x:Name="btnNotification" FontFamily="Segoe UI Symbol" FontSize="20" Content="🔔" Command="{Binding LoadNotification}" Click="btnNotification_Click"/>
<Popup Name="NotificationPopup" IsOpen="False" Closed="PopupClosed" StaysOpen="False" PlacementTarget="{Binding ElementName=btnNotification}" Placement="Bottom" VerticalOffset="20">
<Grid x:Name="PopUpGrid" Height="560" Width="360" Background="White">
<StackPanel Orientation="Vertical" HorizontalAlignment="Right">
<Button BorderBrush="Transparent" BorderThickness="0" Background="White" >
<StackPanel Width="{Binding ActualWidth, ElementName=PopUpGrid}" Orientation="Vertical">
<WrapPanel>
<Rectangle Width="20"/>
<TextBlock Text="Notifications" Width="300" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="24" FontWeight="Light" />
<Button Click="btnNotification_Click" >
<StackPanel>
<TextBlock Text="✕" Foreground="Black" FontWeight="ExtraLight"/>
</StackPanel>
</Button>
</WrapPanel>
<Grid>
<!--Datagrid-->
</Grid>
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Popup>
MainWindow.xaml.cs
public void PopupClosed(object sender, EventArgs e)
{
NotificationPopup.IsOpen = false;
}
答案 0 :(得分:1)
您要实现的目标,违反了“正常”的Windows行为。实际上,这是由操作系统管理的。
但是如果你仍想要覆盖默认操作系统的行为,你需要做一些低级别的Windows消息魔术。
我有一个解决方案,这是一个简单的附加属性,可以用于所有Popup
。就像那样:
<Popup local:PopupMouseEnhance.Enabled="True">
<!-- your content here -->
</Popup>
但是,幕后会发生一些事情,所以我会尝试解释一下。以下是我为您创建的附加属性的完整来源。阅读评论以了解正在发生的事情。
static class PopupMouseEnhance
{
// This is the usual attached property stuff...
public static bool GetEnabled(UIElement element)
{
return (bool)element.GetValue(EnabledProperty);
}
public static void SetEnabled(UIElement element, bool value)
{
element.SetValue(EnabledProperty, value);
}
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.RegisterAttached(
"Enabled",
typeof(bool),
typeof(PopupMouseEnhance),
new PropertyMetadata(false, EnabledChanged));
// This method is called when you set the attached property value
private static void EnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Popup popup = d as Popup;
if (popup == null)
{
// We don't support anything but Popups
throw new InvalidOperationException("This attached property can only be set on a Popup object.");
}
if ((bool)e.NewValue)
{
// if the attached property value is 'true', then enable our trick...
popup.Opened += Popup_Opened;
// This is to prevent memory leaks when Popups get removed from the visual tree
popup.Unloaded += Popup_Unloaded;
}
else
{
// ... otherwise, disable
popup.Unloaded -= Popup_Unloaded;
popup.Opened -= Popup_Opened;
}
}
private static void Popup_Unloaded(object sender, RoutedEventArgs e)
{
// When a Popup is completely unloaded, unsubscribe from everything!
// This event won't be raised on app's shutdown, but in that case
// we don't bother with memory leaks anyway.
Popup p = (Popup)sender;
p.Unloaded -= Popup_Unloaded;
p.Opened -= Popup_Opened;
}
private static void Popup_Opened(object sender, EventArgs e)
{
Popup p = (Popup)sender;
// Okay, the Popup is shown. Enable our tricks!
// First, we determine the window we will monitor:
Window w = Window.GetWindow(p);
if (w != null)
{
// Then, we need a HwndSource instance of that window
// to be able to insert our custom Message Hook
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(w).Handle);
if (source != null)
{
// All set, enable our custom window helper!
WindowHelper.Enable(source, w, p);
}
}
}
// Our custom helper class. The magic occurs here.
private class WindowHelper
{
private readonly HwndSource mHwndSource;
private readonly Window mWindow;
private WindowHelper(HwndSource hwndSource, Window window)
{
mHwndSource = hwndSource;
mWindow = window;
}
public static void Enable(HwndSource hwndSource, Window window, Popup popup)
{
// Create an instance of our helper class...
WindowHelper helper = new WindowHelper(hwndSource, window);
// ... and set a Message Hook to our custom method.
hwndSource.AddHook(helper.WndProc);
// Don't forget to disable the magic, when the popup is closed.
popup.Closed += helper.Popup_Closed;
}
private void Popup_Closed(object sender, EventArgs e)
{
// The Popup is closed now - disable all!
Popup p = (Popup)sender;
p.Closed -= Popup_Closed;
mHwndSource.RemoveHook(WndProc);
}
// This is our custom Windows messages hook.
// This method will be called whenever our window receives a message.
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// We're only interested in the WM_SETCURSOR message.
// It will be sent to our window when the user moves the mouse
// cursor around and clicks the mouse buttons.
if (msg != NativeConstants.WM_SETCURSOR)
{
return IntPtr.Zero;
}
// Determine the necessary parameters.
// See MSDN topic on WM_SETCURSOR for details.
var mouseMessage = ((int)lParam & 0xFFFF0000) >> 16;
var hitTest = (int)lParam & 0xFFFF;
switch (hitTest)
{
// Only continue if the mouse is over
// 'minimize', 'maximize', 'close'
case NativeConstants.HTMINBUTTON:
case NativeConstants.HTMAXBUTTON:
case NativeConstants.HTCLOSE:
break;
default:
// Otherwise, do nothing.
return IntPtr.Zero;
}
// If the user clicks outside the Popup,
// a WM_MOUSEMOVE message will be transmitted via WM_SETCURSOR.
// So if we've received something other - ignore that.
if (mouseMessage != NativeConstants.WM_MOUSEMOVE)
{
return IntPtr.Zero;
}
// We need to perform these actions manually,
// because the window will not receive the corresponding messages
// on first mouse click (when the Popup is still open).
switch (hitTest)
{
case NativeConstants.HTMINBUTTON:
mWindow.WindowState = WindowState.Minimized;
break;
case NativeConstants.HTMAXBUTTON:
mWindow.WindowState = WindowState.Maximized;
break;
case NativeConstants.HTCLOSE:
mWindow.Close();
break;
}
// We always return 0, because we don't want any side-effects
// in the message processing.
return IntPtr.Zero;
}
}
private static class NativeConstants
{
public const int WM_SETCURSOR = 0x020;
public const int WM_MOUSEMOVE = 0x200;
public const int HTMINBUTTON = 8;
public const int HTMAXBUTTON = 9;
public const int HTCLOSE = 20;
}
}
希望这有帮助!