Emulando as caixas de diálogo ícone de notificação de Vista com WPF
-
21-08-2019 - |
Pergunta
Quando um único clique um ícone de notificação na Vista (como os ícones de rede ou som) que você é apresentado com um diálogo ainda captionless delimitada ( http://i.msdn.microsoft.com/Aa511448.NotificationArea22 (pt-br, MSDN.10) .png ):
http: //i.msdn. microsoft.com/Aa511448.NotificationArea22(en-us,MSDN.10).png
Como posso emular estes em WPF? Criando uma nova janela e definindo WindowStyle para "Nenhum" e ResizeMode para "CanResize" produz um resultado próximo, exceto que o quadro é um pouco magra demais eo diálogo é redimensionável, o que é indesejável. Definir ResizeMode para resultados "noresize" em uma janela com nenhuma borda Aero (apenas uma 2px borda fina linha sólida).
Solução 2
Eu finalmente descobri-lo: Se você definir WindowStyle para "Nenhum" e ResizeMode para "CanResize", então você vai ter a borda espessa correta sem uma legenda, o único engate é que você ainda pode redimensionar a janela
Felizmente, este problema é facilmente corrigidas pela manipulação WM_NCHITTEST para a instância Window
:
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;
}
Por nunca deixando o Windows sabe que o cursor está em uma borda, nós nunca será presenteado com um cursor de redimensionamento.
Outras dicas
O truque é adicionar o limite de seu self. Eu fiz isso, fazendo o principal elemento de conteúdo de um DockPanel e adicionar uma borda. Você pode usar a fronteira para personalizar a aparência para combinar as janelas Vista estilo. Eu não sou bom com as cores, então não posso citar que um particular, mas usados ??Cinzento como um exemplo.
Tente o seguinte
<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>
O que você precisa é especificar a combinação certa de estilos de janela, WPF não expor todas as opções disponíveis no Windows, mas você pode configurá-los você mesmo usando pinvoke.
Eu não estou em uma máquina com o Vista agora, então eu não posso combinação estilo de teste para ver o que dá a aparência correta, mas a lista de estilos (em C #) é aqui http://pinvoke.net/default.aspx/user32/GetWindowLong.html
em que você está classe Window:
[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);
}
eu percebi que eu postar o que eu vim acima com a medida. Isso fica bem perto:
<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>
É claro que eles estão usando mais do que apenas uma transparência na ActiveWindowBorderColor desenhar no meio da fronteira. Parece que a top 1/4 tem uma sobreposição de branco, enquanto a parte inferior 3/4 tem uma capa preta. Também a fronteira exterior tem uma cor de destaque nas bordas direita e inferior. Se eu fosse fazer isso de verdade eu iria criar um UserControl que deriva de Fronteira para lidar com todos os pequenos detalhes como esse (e permitam-me para redimensionar se eu quiser) e jogar o estilo da janela em um dicionário de recursos.