Emuliert die Vista-Benachrichtigungssymbol Dialogfelder mit WPF
-
21-08-2019 - |
Frage
Wenn ein Benachrichtigungssymbol in Vista (wie das Netzwerk oder Sound Icons) ein einzelnen Klicken Sie mit einem grenzte noch captionless Dialog präsentiert werden ( http://i.msdn.microsoft.com/Aa511448.NotificationArea22 (de-de, MSDN.10) .png ):
http: //i.msdn. microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png
Wie kann ich emulieren diese in WPF? Erstellen Sie ein neues Fenster und Einstellung Window auf „None“ und ResizeMode auf „CanResize“ erzeugt ein knappes Ergebnis, außer dass der Rahmen etwas zu dünn ist und der Dialog ist veränderbar, was unerwünscht ist. Einstellen ResizeMode auf „noresize“ Ergebnisse in einem Fenster ohne Aero Grenze (nur eine dünne 2px gezogene Linie Grenze.)
Lösung 2
Habe ich es endlich heraus: Wenn Sie Window auf „None“ und ResizeMode auf „CanResize“ gesetzt, dann werden Sie die richtige dicke Grenze ohne Beschriftung erhalten, das einzige Problem ist, dass Sie das Fenster noch die Größe verändern können.
Zum Glück dieses Problem leicht durch den Umgang mit WM_NCHITTEST für Ihre Window
Instanz behoben ist:
private IntPtr _hwnd;
protected override void OnSourceInitialized(EventArgs e) {
_hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
System.Windows.Interop.HwndSource.FromHwnd(_hwnd).AddHook(_WndProc);
base.OnSourceInitialized(e);
}
private const int WM_NCHITTEST = 132;
private const int HTCLIENT = 1;
private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
// We should only receive messages for our own window handle.
System.Diagnostics.Debug.Assert(hwnd == _hwnd);
if (msg == WM_NCHITTEST) {
handled = true;
return (IntPtr)HTCLIENT;
}
return IntPtr.Zero;
}
Durch die nie im Stich gelassen von Windows weiß, dass der Cursor an einer Grenze ist, werden wir nie mit einer Größe ändern Cursor dargestellt werden.
Andere Tipps
Der Trick ist, die Grenze, um sich selbst hinzuzufügen. Ich tat dies, indem das Hauptinhaltselement ein DockPanel machen und das Hinzufügen einer Grenze. Sie können die Grenze verwenden um das Aussehen anpassen, um den Vista Style Fenster passen. Ich bin nicht gut mit Farben, damit ich nicht, dass insbesondere einen Namen kann aber verwendet Grau als Beispiel.
Versuchen Sie, die folgende
<Window x:Class="WpfApplication10.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
WindowStyle="None"
ResizeMode="NoResize">
<DockPanel>
<Border
BorderBrush="Gray"
BorderThickness="5">
<TextBlock>Here we go</TextBlock>
</Border>
</DockPanel>
</Window>
Was Sie brauchen, ist die richtige Kombination von Fensterstile angeben, nicht WPF nicht alle Optionen in Windows zur Verfügung aussetzen, aber man kann sie selbst mit pinvoke eingestellt.
Ich bin nicht auf einem Vista-Rechner jetzt so kann ich nicht Artkombination testen, um zu sehen, was das richtige Aussehen gibt, aber die Liste der Arten (in C #) ist hier http://pinvoke.net/default.aspx/user32/GetWindowLong.html
Du bist Window-Klasse:
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 SWP_NOZORDER = 0x0004;
private const UInt32 SWP_NOREDRAW = 0x0008;
private const UInt32 SWP_NOACTIVATE = 0x0010;
private const UInt32 SWP_FRAMECHANGED = 0x0020;
public override void OnSourceInitialized(EventArgs e)
{
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
// set styles to a combination of WS_ flags and exstyles to a combination of WS_EX_ flags
SetWindowLong(hwnd, GWL_STYLE, styles);
SetWindowLong(hwnd, GWL_EXSTYLE, exstyles);
// and to activate changes:
SetWindowPos(hwnd,IntPtr.Zero,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
}
Ich dachte, ich würde schreiben, was ich mit so weit habe kommen. Dies wird ziemlich nahe:
<Window.Style>
<Style TargetType="{x:Type Window}">
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderThickness="1" CornerRadius="4" Background="{x:Null}">
<Border.BorderBrush>
<SolidColorBrush Color="{x:Static SystemColors.WindowFrameColor}" Opacity="0.75" />
</Border.BorderBrush>
<Border BorderThickness="5" Background="{x:Null}">
<Border.BorderBrush>
<SolidColorBrush Color="{x:Static SystemColors.ActiveBorderColor}" Opacity="0.5" />
</Border.BorderBrush>
<Border BorderThickness="1" Background="White">
<Border.BorderBrush>
<SolidColorBrush Color="{x:Static SystemColors.WindowFrameColor}" Opacity="0.75" />
</Border.BorderBrush>
<ContentPresenter />
</Border>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Style>
Selbstverständlich sind sie mit mehr als nur eine Transparenz auf dem ActiveWindowBorderColor die Mitte der Grenze zu ziehen. Es scheint, dass die oberen 1/4 ein weißes Overlay hat, während die unteren 3/4 einen schwarzen Overlay hat. Auch der äußere Rand hat eine Akzentfarbe auf der rechten und unteren Rand. Wenn ich das richtig tun, würde ich ein Benutzersteuerelement erstellen, die von Border stammen wie das all die kleinen Details zu behandeln (und ich erlauben, um die Größe, wenn ich will) und das Fenster Stil in ein Ressourcenverzeichnis werfen.