Я пошел вперед и создал сайт CodePlex для этого, что включает в себя «Toast Всплывающие» и управления «Справка» Воздушные шары. Эти версии имеют больше возможностей, чем то, что описано ниже. Code Plex Project.
Вот ссылка на Nuget Package
Вот мое решение для баллонной подписи. Некоторые из вещей, которые я хотел бы сделать по-другому:
- Затухание при входе мыши.
- Увядайте, когда мышь уходит и закрывает окно, когда прозрачность достигает 0.
- Если мышь над окном, непрозрачность будет на 100% и не будет закрыта.
- Высота окна воздушного шара динамична.
- Используйте триггеры событий вместо таймеров.
- Расположите воздушный шар на левой или правой стороне элемента управления.
Вот Помощь изображения, которые я использовал.
Я создал UserControl со значком простого "Помощь".
<UserControl x:Class="Foundation.FundRaising.DataRequest.Windows.Controls.HelpBalloon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Name="HelpBalloonControl"
d:DesignHeight="20" d:DesignWidth="20" Background="Transparent">
<Image Width="20" Height="20"
MouseEnter="ImageMouseEnter"
Cursor="Hand"
IsManipulationEnabled="True"
Source="/Foundation.FundRaising.DataRequest.Windows;component/Resources/help20.png" />
И добавили этот код позади.
public partial class HelpBalloon : UserControl
{
private Balloon balloon = null;
public HelpBalloon()
{
InitializeComponent();
}
public string Caption { get; set; }
public Balloon.Position Position { get; set; }
private void ImageMouseEnter(object sender, MouseEventArgs e)
{
if (balloon == null)
{
balloon = new Balloon(this, this.Caption);
balloon.Closed += BalloonClosed;
balloon.Show();
}
}
private void BalloonClosed(object sender, EventArgs e)
{
this.balloon = null;
}
}
Вот код XAML для окна воздушного шара, который открывается UserControl.
<Window x:Class="Foundation.FundRaising.DataRequest.Windows.Balloon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="90" Width="250" WindowStyle="None"
ResizeMode="NoResize" ShowInTaskbar="False"
Topmost="True" IsTabStop="False"
OverridesDefaultStyle="False"
SizeToContent="Height"
AllowsTransparency="True"
Background="Transparent" >
<Grid RenderTransformOrigin="0,1" >
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="Path">
<Setter Property="Fill" Value="#fdfdfd"/>
<Setter Property="Stretch" Value="Fill"/>
<Setter Property="Width" Value="22"/>
<Setter Property="Height" Value="31"/>
<Setter Property="Panel.ZIndex" Value="99"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="#FF757575" Opacity=".7"/>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<Path
HorizontalAlignment="Left"
Margin="15,3,0,0"
Data="M10402.99154,55.5381L10.9919,0.64 0.7,54.9"
x:Name="PathPointLeft"/>
<Path
HorizontalAlignment="Right"
Margin="175,3,0,0"
Data="M10402.992,55.5381 L10284.783,3.2963597 0.7,54.9"
x:Name="PathPointRight">
</Path>
</StackPanel>
<Border Margin="5,-3,5,5"
CornerRadius="7" Panel.ZIndex="100"
VerticalAlignment="Top">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<LinearGradientBrush.RelativeTransform>
<RotateTransform Angle="90" CenterX="0.7" CenterY="0.7" />
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="#FFFDFDFD" Offset=".2"/>
<GradientStop Color="#FFB6FB88" Offset=".8"/>
</LinearGradientBrush>
</Border.Background>
<Border.Effect>
<DropShadowEffect Color="#FF757575" Opacity=".7"/>
</Border.Effect>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Width="35"
Margin="5"
VerticalAlignment="Top" Height="35"
Source="Resources/help.png" />
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Margin="0,10,10,10"
TextOptions.TextFormattingMode="Display"
x:Name="textBlockCaption"
Text="This is the caption"/>
</Grid>
</Border>
</StackPanel>
<!-- 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:3" BeginTime="0:0:3" 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:2" BeginTime="0:0:1" Completed="DoubleAnimationCompleted"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
И код позади окна Balloon.
public partial class Balloon : Window
{
public enum Position
{
Left,
Right
}
public Balloon(Control control, string caption, Position position)
{
InitializeComponent();
this.textBlockCaption.Text = caption;
// Compensate for the bubble point
double captionPointMargin = this.PathPointLeft.Margin.Left;
Point location = GetControlPosition(control);
if (position == Position.Left)
{
this.PathPointRight.Visibility = Visibility.Hidden;
this.Left = location.X + (control.ActualWidth/2) - captionPointMargin;
}
else
{
this.PathPointLeft.Visibility = Visibility.Hidden;
this.Left = location.X - this.Width + control.ActualWidth + (captionPointMargin/2);
}
this.Top = location.Y + (control.ActualHeight/2);
}
private static Point GetControlPosition(Control control)
{
Point locationToScreen = control.PointToScreen(new Point(0, 0));
var source = PresentationSource.FromVisual(control);
return source.CompositionTarget.TransformFromDevice.Transform(locationToScreen);
}
private void DoubleAnimationCompleted(object sender, EventArgs e)
{
if (!this.IsMouseOver)
{
this.Close();
}
}
}
Я уже дал ответ в следующей ссылке. Пожалуйста, следуйте им. [Как создать воздушный шар для Caps Lock предупреждение] [1] [1]: http://stackoverflow.com/questions/1092808/wpf-warn-about-capslock/8060520#8060520 –