Estoy usando .NET y estoy creando una aplicación de escritorio/servicio que mostrará las notificaciones en la esquina de mi Escritorio cuando se desencadenen ciertos eventos. No quiero utilizar un cuadro de mensaje normal b/c que sería demasiado intrusivo. Quiero que las notificaciones se deslicen a la vista y luego desaparezcan después de unos segundos. Estoy pensando en algo que se parecerá mucho a las alertas de Outlook que uno recibe cuando llega un nuevo mensaje. La pregunta es: ¿Debería usar WPF para esto? Nunca he hecho nada con WPF, pero lo intentaré felizmente si es lo mejor para el final. ¿Hay alguna manera de lograr esto con las librerías .NET regulares?Crear notificaciones emergentes de "tostadora" en Windows con .NET
Respuesta
WPF hace esto absolutamente trivial: Tomaría probablemente diez minutos o menos. Estos son los pasos:
- crear una ventana, establecer AllowsTransparency = "true" y añadir una rejilla para que
- Establecer RenderTransform de la cuadrícula a un ScaleTransform con origen de 0,1
- Crear una animación en la cuadrícula que anima a ScaleX 0 a 1 luego anima la opacidad de 1 a 0
- En el constructor, calcule Window.Top y Window.Left para colocar la ventana en la esquina inferior derecha de la pantalla.
Eso es todo.
Usando Expression Blend tardó aproximadamente 8 minutos mí para generar el siguiente código de trabajo:
<Window
x:Class="NotificationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Notification Popup" Width="300" SizeToContent="Height"
WindowStyle="None" AllowsTransparency="True" Background="Transparent">
<Grid RenderTransformOrigin="0,1" >
<!-- Notification area -->
<Border BorderThickness="1" Background="Beige" BorderBrush="Black" CornerRadius="10">
<StackPanel Margin="20">
<TextBlock TextWrapping="Wrap" Margin="5">
<Bold>Notification data</Bold><LineBreak /><LineBreak />
Something just happened and you are being notified of it.
</TextBlock>
<CheckBox Content="Checkable" Margin="5 5 0 5" />
<Button Content="Clickable" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<!-- Animation -->
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
</Window>
Con código detrás:
using System;
using System.Windows;
using System.Windows.Threading;
public partial class NotificationWindow
{
public NotificationWindow()
{
InitializeComponent();
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
{
var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
this.Left = corner.X - this.ActualWidth - 100;
this.Top = corner.Y - this.ActualHeight;
}));
}
}
Desde WPF es una de las bibliotecas .NET regulares, el la respuesta es sí, es es posible para lograr esto con las "bibliotecas .NET regulares".
Si está preguntando si hay una forma de hacerlo sin usar WPF, la respuesta es sí, pero es extremadamente compleja y tomará más de 5 días que 5 minutos.
Esto es genial. Funciona de maravilla. ¡Gracias! Impresionante qué tan poco código tomó. – Antony
+ ¡Genial, me has ahorrado un poco de tiempo también! Gracias) –
No estoy seguro si esto es necesario, pero agregué un evento Completado a la animación de opacidad, y en el código detrás agregué "this.Close();". De lo contrario, la ventana siempre estaría abierta. Puede estropear una aplicación que se cierra en función del cierre de la última ventana. – Paul
Tenga en cuenta que el subproceso de llamada debe ser sta debido a que muchos componentes de interfaz de usuario requieren de este, mientras que la escritura siguiente código bajo System.Timers.Timer transcurrido evento
Window1 notifyWin = new Window1();
bool? isOpen = notifyWin.ShowDialog();
if (isOpen != null && isOpen == true)
{
notifyWin.Close();
}
System.Threading.Thread.Sleep(1000);
notifyWin.ShowDialog();
bajo window1 constructor:
public Window1()
{
InitializeComponent();
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => {
var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
this.Left = corner.X - this.ActualWidth - 100;
this.Top = corner.Y - this.ActualHeight;
}));
}
public partial class NotificationWindow : Window
{
DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
public NotificationWindow()
: base()
{
this.InitializeComponent();
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
{
var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
this.Left = corner.X - this.ActualWidth;
this.Top = corner.Y - this.ActualHeight;
}));
timer.Interval = TimeSpan.FromSeconds(4d);
timer.Tick += new EventHandler(timer_Tick);
}
public new void Show()
{
base.Show();
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
//set default result if necessary
timer.Stop();
this.Close();
}
}
El código anterior es versión refinada @Ray Burns. Agregado con código de intervalo de tiempo. De manera que la ventana de notificación de cerraría después de 4 segundos ..
de llamadas La ventana como,
NotificationWindow nfw = new NotificationWindow();
nfw.Show();
Aaahaaaaaaan. . – Gopichandar
@Gopichandar No pude entender Gopi –
que siguió adelante y creó un sitio CodePlex para este que incluye "Toast Popups" y "control de globos de ayuda" . Estas versiones tienen más características que las que se describen a continuación. https://toastspopuphelpballoon.codeplex.com.
Este fue un gran punto de partida para la solución que estaba buscando.He hecho un par de modificaciones para cumplir con mis requisitos:
- Quería detener la animación sobre el mouse.
- Animación "Restablecer" cuando el mouse se va.
- cerrar la ventana cuando la opacidad llegó a 0.
- Pila del pan tostado (no he resuelto el problema si el número de ventanas excede la altura de la pantalla) Carga
- llamada de mi modelo de vista
Aquí está mi XAML
<Window x:Class="Foundation.FundRaising.DataRequest.Windows.NotificationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="NotificationWindow" Height="70" Width="300" ShowInTaskbar="False"
WindowStyle="None" AllowsTransparency="True"
Background="Transparent">
<Grid RenderTransformOrigin="0,1" >
<Border BorderThickness="2" Background="{StaticResource GradientBackground}" BorderBrush="DarkGray" CornerRadius="7">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Column="0"
Grid.RowSpan="2"
Source="Resources/data_information.png"
Width="40" Height="40"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<Image Grid.Column="2"
Source="Resources/error20.png"
Width="20"
Height="20"
VerticalAlignment="Center"
ToolTip="Close"
HorizontalAlignment="Center"
Cursor="Hand" MouseUp="ImageMouseUp"/>
<TextBlock Grid.Column="1"
Grid.Row="0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontWeight="Bold" FontSize="15"
Text="A Request has been Added"/>
<Button Grid.Column="1"
Grid.Row="1"
FontSize="15"
Margin="0,-3,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="Click Here to View"
Style="{StaticResource LinkButton}"/>
</Grid>
</Border>
<!-- Animation -->
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="StoryboardLoad">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)" From="0.0" To="1.0" Duration="0:0:2" />
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)" From="1.0" To="0.0" Duration="0:0:8" BeginTime="0:0:5" Completed="DoubleAnimationCompleted"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<RemoveStoryboard BeginStoryboardName="StoryboardLoad"/>
<RemoveStoryboard BeginStoryboardName="StoryboardFade"/>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard x:Name="StoryboardFade">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)" From="1.0" To="0.0" Duration="0:0:8" BeginTime="0:0:2" Completed="DoubleAnimationCompleted"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
el código detrás
public partial class NotificationWindow : Window
{
public NotificationWindow()
: base()
{
this.InitializeComponent();
this.Closed += this.NotificationWindowClosed;
}
public new void Show()
{
this.Topmost = true;
base.Show();
this.Owner = System.Windows.Application.Current.MainWindow;
this.Closed += this.NotificationWindowClosed;
var workingArea = Screen.PrimaryScreen.WorkingArea;
this.Left = workingArea.Right - this.ActualWidth;
double top = workingArea.Bottom - this.ActualHeight;
foreach (Window window in System.Windows.Application.Current.Windows)
{
string windowName = window.GetType().Name;
if (windowName.Equals("NotificationWindow") && window != this)
{
window.Topmost = true;
top = window.Top - window.ActualHeight;
}
}
this.Top = top;
}
private void ImageMouseUp(object sender,
System.Windows.Input.MouseButtonEventArgs e)
{
this.Close();
}
private void DoubleAnimationCompleted(object sender, EventArgs e)
{
if (!this.IsMouseOver)
{
this.Close();
}
}
}
la llamada desde el ViewModel:
private void ShowNotificationExecute()
{
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(
() =>
{
var notify = new NotificationWindow();
notify.Show();
}));
}
Los estilos referencia en el XAML:
<Style x:Key="LinkButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock>
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Cursor" Value="Hand"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextDecorations="Underline" Text="{TemplateBinding Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<LinearGradientBrush x:Key="GradientBackground" EndPoint="0.504,1.5" StartPoint="0.504,0.03">
<GradientStop Color="#FFFDD5A7" Offset="0"/>
<GradientStop Color="#FFFCE79F" Offset="0.567"/>
</LinearGradientBrush>
UPDATE: añadí este controlador de eventos cuando se cierra el formulario a "drop "las otras ventanas".
private void NotificationWindowClosed(object sender, EventArgs e)
{
foreach (Window window in System.Windows.Application.Current.Windows)
{
string windowName = window.GetType().Name;
if (windowName.Equals("NotificationWindow") && window != this)
{
// Adjust any windows that were above this one to drop down
if (window.Top < this.Top)
{
window.Top = window.Top + this.ActualHeight;
}
}
}
}
¿Cómo funciona NotificationWindowClosed? No se hace referencia en ningún otro lugar en el código – HoKy22
. Disculpa. He agregado el código faltante. Este ha sido un trabajo en progreso, y lo eché de menos en la última actualización. – LawMan
¡Funciona a la perfección! ¿Puede explicar un poco más sobre el significado de "Agregué este controlador de eventos cuando el formulario está cerrado para" soltar "las otras ventanas". ¿Qué quieres decir con "dejar caer"? – HoKy22
NotifyIcon notifyIcon = new NotifyIcon();
Stream iconStream = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/Assets/ic_instant_note_tray.ico")).Stream;
notifyIcon.Icon = new System.Drawing.Icon(iconStream);
notifyIcon.Text = string.Format(Properties.Resources.InstantNoteAppName, Constants.Application_Name);
notifyIcon.Visible = true;
notifyIcon.ShowBalloonTip(5000, "tooltiptitle", "tipMessage", ToolTipIcon.Info);
notifyIcon.Visible = false;
notifyIcon.Dispose();
- 1. Notificaciones emergentes de KDE en xmonad
- 2. Evite ventanas emergentes de Windows Firewall con sockets en localhost
- 3. Cómo crear ventanas emergentes en Rails 3.1
- 4. Drupal: crear contenido en ventanas emergentes/lightbox?
- 5. Biblioteca de notificaciones para Windows
- 6. ¿Podemos crear alertas de error emergentes en java?
- 7. Crear JSON con .net
- 8. Crear ventanas emergentes informativas/información sobre herramientas en Cocoa
- 9. Salidas de notificaciones de estilo de Windows 7 en Delphi
- 10. Memcached con Windows y .NET
- 11. Envío de notificaciones con GObjects
- 12. MVC-ventanas emergentes
- 13. menús emergentes
- 14. Menús emergentes GLUT
- 15. Integración de Windows Shell con .NET
- 16. Crear varias PC virtuales de Windows con Windows XP Mode
- 17. Autenticación de Windows en .NET
- 18. iPhone: notificaciones locales diarias
- 19. cómo crear notificaciones locales en la aplicación iphone
- 20. jQuery cola en Chrome userscript con ventanas emergentes?
- 21. Biblioteca de notificaciones de Python multiplataforma
- 22. Aero Glass Bordes de Ventanas Emergentes en C#
- 23. Selenium: Ventanas emergentes de prueba
- 24. Problema extraño con un servicio Windows .NET
- 25. Watin: cómo probar el sitio con las páginas emergentes
- 26. Crear usuario local con PowerShell (Windows Vista)
- 27. ¿Cómo crear archivos .odt con C# .NET?
- 28. Obligaciones de notificaciones push con Titanium & XCode
- 29. Bluetooth API en Windows/.Net?
- 30. iphone y notificaciones: ¿número máximo de notificaciones?
Creo que de alguna manera es posible con .Net regular, Infragistics logró hacerlo: http://www.infragistics.com/dotnet/netadvantage/winforms/windesktopalert.aspx#Overview –
Sí, eso es exactamente lo que quise decir. Gente, por favor comparte tus pensamientos. Solo busco una dirección general, no un procedimiento detallado. Gracias. – Antony
aquí es uno que ha estado en codeProject por un tiempo. http://www.codeproject.com/KB/miscctrl/taskbarnotifier.aspx tomará menos de 5 días. – quimbo