How to add scrolling/moving text in textblock in xaml - c#

I want to add a scrolling/moving text(from right to left) in the textblock.
It should scroll one time only.
I have Googled it but didn't find anything.
I want to scroll the text in the textblock (not the whole textblock) only once. Then scrolling should be stopped.
I found this code on net but it is not what I want. I want to scroll the text 1 time and then stop scrolling. Any idea how to do that?
<TextBlock FontSize="22" x:Name="txtScrolling" Margin="1386,208,-616,460">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="translate" />
</TextBlock.RenderTransform>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="1">
<DoubleAnimation
From="1000" To="-1000"
Storyboard.TargetName="translate"
Storyboard.TargetProperty="X"
Duration="0:0:10" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
This is the Text to Scroll
</TextBlock>

You could try something like this..
This is an xaml example:
<Grid>
<ScrollViewer x:Name="Scroll_Content" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto" CanContentScroll="True" VerticalAlignment="Center" HorizontalAlignment="Center" Width="250" FlowDirection="RightToLeft">
<TextBlock Text="Hello World ------------ Hello World ------------ Hello World -------- Hello World"></TextBlock>
</ScrollViewer>
<Button x:Name="Start_Timer" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,10" Width="100" Height="50" Content="Start Timer" Click="Start_Timer_Click"/>
</Grid>
Code behind:
DispatcherTimer timer1 = new DispatcherTimer();
double num = 0;
public MainWindow()
{
InitializeComponent();
timer1.Interval = new TimeSpan(0,0,0,0,250);
timer1.Tick += timer1_Tick;
}
void timer1_Tick(object sender, EventArgs e)
{
try
{
Scroll_Content.ScrollToHorizontalOffset(num);
num++;
}
catch { }
}
void Start_Timer_Click(object sender, RoutedEventArgs e)
{
if (timer1.IsEnabled == false)
{
num = 0;
timer1.Start();
}
else
timer1.Stop();
}

Related

Why do mouse events not work with same events in parent object?

I have two borders that are replacing each other via animation, triggered by MouseEnter and MouseLeave events. And I also have a button on one of the borders with MouseEnter="Test_MouseEnter" MouseDown="Test_MouseDown".
XAML:
<UserControl.Resources>
<Storyboard x:Key="FirstCardStoryboard">
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetName="FirstBorder"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
<Storyboard x:Key="SecondCardStoryboard">
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetName="SecondBorder"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</UserControl.Resources>
<Grid MouseEnter="Grid_MouseEnter" MouseLeave="Grid_MouseLeave">
<Border x:Name="FirstBorder" Width="170" Height="210" CornerRadius="15" BorderThickness="2" Background="#FF323236" BorderBrush="Cyan">
<StackPanel VerticalAlignment="Center">
<Button x:Name="Test" Width="130" Height="30" MouseEnter="Test_MouseEnter" Click="Test_Click">
</Button>
</StackPanel>
</Border>
<Border x:Name="SecondBorder" Width="170" Height="210" CornerRadius="15" BorderThickness="2"
Background="#FF323236" BorderBrush="Cyan" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
</Grid>
</Border>
</Grid>
And the C# side:
public partial class ProductControl : UserControl
{
public ProductControl()
{
InitializeComponent();
}
private void Grid_MouseEnter(object sender, MouseEventArgs e)
{
Storyboard storyboard = (this.Resources["FirstCardStoryboard"] as Storyboard);
DoubleAnimation animation = storyboard.Children.First() as DoubleAnimation;
animation.To = 1;
storyboard.Begin();
Storyboard storyboardSecond = (this.Resources["SecondCardStoryboard"] as Storyboard);
DoubleAnimation animationSecond = storyboardSecond.Children.First() as DoubleAnimation;
animationSecond.To = 0;
storyboardSecond.Begin();
}
private void Grid_MouseLeave(object sender, MouseEventArgs e)
{
Storyboard storyboard = (this.Resources["FirstCardStoryboard"] as Storyboard);
DoubleAnimation animation = storyboard.Children.First() as DoubleAnimation;
animation.To = 0;
storyboard.Begin();
Storyboard storyboardSecond = (this.Resources["SecondCardStoryboard"] as Storyboard);
DoubleAnimation animationSecond = storyboardSecond.Children.First() as DoubleAnimation;
animationSecond.To = 1;
storyboardSecond.Begin();
}
private void Test_MouseEnter(object sender, MouseEventArgs e)
{
}
private void Test_Click(object sender, RoutedEventArgs e)
{
}
}
Then I put breakpoints on Test_MouseEnter and Test_MouseDown methods, but it seems that they do not call, when I move mouse over the button or click on it.
Is this because of the Grid with MouseEnter="Grid_MouseEnter" MouseLeave="Grid_MouseLeave" or is there another reason of this? If the Grid stops events, is the a way to pass on this events?
I tested Click="Test_Click" on the button, but this also doesn't work.
I found the problem. I was changing only opacity of the borders, but they were still there. So the Second Border handled all the events. So I also need to change Visibility of the borders in animation.
Or as #Clemens said I can change just IsHitTestVisible.

C#/WPF Handling active Storyboard Animations when spamming the 'Toggle'

Basically I have this animation where when you click the button(s), it toggles the grid either revealing or hiding the 2nd column (which contains Button2) ... My problem is that when you spam-click the button, the animation gets queued so it needs to finish the first animation before doing the second one. The only workaround I have is to disable the button while the animation is active then re-enabling them once the animation is completed. But I'm trying to find a way where the active animation gets interrupted somehow and instead uses the current width of the grid to start the 2nd animation.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_toggle = false;
GridBodyWidthOne = new GridLength(1, GridUnitType.Star);
GridBodyWidthZero = new GridLength(0, GridUnitType.Star);
GridBody0Width = GridBodyWidthOne;
GridBody1Width = GridBodyWidthZero;
storyboard = this.FindResource("expandBody0") as Storyboard;
storyboard.FillBehavior = FillBehavior.Stop;
storyboard.Completed += (object o, EventArgs ea) => {
GridBody0.Width = GridBodyWidthOne;
GridBody1.Width = GridBodyWidthZero;
GridBody0.BeginAnimation(ColumnDefinition.WidthProperty, null);
GridBody1.BeginAnimation(ColumnDefinition.WidthProperty, null);
GridSplitter0.IsEnabled = false;};
storyboard = this.FindResource("retractBody0") as Storyboard;
storyboard.FillBehavior = FillBehavior.Stop;
storyboard.Completed += (object o, EventArgs ea) => {
GridBody0.Width = GridBodyWidthOne;
GridBody1.Width = GridBodyWidthOne;
GridBody0.BeginAnimation(ColumnDefinition.WidthProperty, null);
GridBody1.BeginAnimation(ColumnDefinition.WidthProperty, null);
GridSplitter0.IsEnabled = true;};
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ToggleMainBody1();
}
private void ToggleMainBody1()
{
double maxWidth = GridBody0.ActualWidth + GridBody1.ActualWidth;
double width0 = GridBody0.ActualWidth / maxWidth;
double width1 = GridBody1.ActualWidth / maxWidth;
GridBody0Width = new GridLength(width0, GridUnitType.Star);
GridBody1Width = new GridLength(width1, GridUnitType.Star);
if (!_toggle)
RevealMainBody1();
else
HideMainBody1();
_toggle = !_toggle;
}
private void HideMainBody1()
{
//storyboard = this.FindResource("retractBody0") as Storyboard;
//storyboard.Stop(this);
storyboard = this.FindResource("expandBody0") as Storyboard;
storyboard.Begin(this);
}
private void RevealMainBody1()
{
//storyboard = this.FindResource("expandBody0") as Storyboard;
//storyboard.Stop(this);
storyboard = this.FindResource("retractBody0") as Storyboard;
storyboard.Begin(this);
}
as for why I have FillBehavior set to 'Stop', I have a problem with the GridSplitter if it's set to 'HoldEnd'. 'HoldEnd' actually works well but not when I adjust it via the GridSplitter. So basically, the problem occurs when you double-click the toggle button (or trigerring the toggle twice without having the first animation finish).
<Window x:Class="ColumnAdjustmentV2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ColumnAdjustmentV2"
xmlns:g="clr-namespace:ColumnAdjustmentV2"
mc:Ignorable="d"
Title="MainWindow" Height="650" Width="800" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged" >
<Window.Resources>
<Storyboard x:Key="expandBody0">
<!--<g:GridLengthAnimation BeginTime="0:0:0" Duration="0:0:0.5" Storyboard.TargetName="GridBody0" Storyboard.TargetProperty="Width" From="{Binding Path=GridBody0Width}" To="{Binding Path=GridBodyWidthOne}" />-->
<g:GridLengthAnimation BeginTime="0:0:0" Duration="0:0:0.5" Storyboard.TargetName="GridBody1" Storyboard.TargetProperty="Width" From="{Binding Path=GridBody1Width}" To="{Binding Path=GridBodyWidthZero}" />
</Storyboard>
<Storyboard x:Key="retractBody0">
<!--<g:GridLengthAnimation BeginTime="0:0:0" Duration="0:0:0.5" Storyboard.TargetName="GridBody0" Storyboard.TargetProperty="Width" From="{Binding Path=GridBody0Width}" To="{Binding Path=GridBodyWidthOne}" />-->
<g:GridLengthAnimation BeginTime="0:0:0" Duration="0:0:0.5" Storyboard.TargetName="GridBody1" Storyboard.TargetProperty="Width" From="{Binding Path=GridBody1Width}" To="{Binding Path=GridBodyWidthOne}" />
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="500" />
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="GridBody0" Width="{Binding Path=GridBody0Width, Mode=TwoWay}" />
<ColumnDefinition x:Name="GridBodyDivider" Width="Auto" />
<ColumnDefinition x:Name="GridBody1" Width="{Binding Path=GridBody1Width, Mode=TwoWay}" />
</Grid.ColumnDefinitions>
<Button x:Name="Button1" Grid.Column="0" Content="Button1" Click="Button_Click" />
<GridSplitter x:Name="GridSplitter0" Grid.Column="1" Background="#FFCC0099" HorizontalAlignment="Center" Margin="0" Width="4" VerticalAlignment="Stretch" LayoutUpdated="GridSplitter_LayoutUpdated" MouseDoubleClick="GridSplitter_MouseDoubleClick" PreviewKeyDown="GridSplitter_PreviewKeyDown" PreviewMouseUp="GridSplitter_PreviewMouseUp" />
<Button x:Name="Button2" Grid.Column="2" Content="Button2" Click="Button_Click" />
</Grid>
<Grid Grid.Row="1">
<Button x:Name="Button3" Content=""/>
</Grid>
</Grid>
https://www.youtube.com/watch?v=2iE8cZC6EFQ
I have prepared a sample project that I think may be helpful for you: https://github.com/Drreamer/AnimationReverse
In this example I resize a button from min to max width using animation. To start animation or to run it in reverse direction simply click the button.
<Grid x:Name="rootGrid">
<Button x:Name="button" MinWidth="40" Width="40" Content="Expand"
local:MainWindow.AnimationDuration="0:0:2" HorizontalAlignment="Left" Click="button_Click" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="button"
Storyboard.TargetProperty="Width"
From="{Binding ActualWidth, ElementName=button}"
Duration="{Binding Path=(local:MainWindow.AnimationDuration), ElementName=button}">
<DoubleAnimation.To>
<MultiBinding Converter="{StaticResource ToWidthConverter}">
<Binding ElementName="button" Path="Tag" />
<Binding ElementName="button" Path="MinWidth" />
<Binding ElementName="rootGrid" Path="ActualWidth" />
</MultiBinding>
</DoubleAnimation.To>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
Here I use binding to dynamically set the To and Duration properties. I store information about current animation direction in the Tag property. The Duration is calculated dynamically from the Button.Click event based on the current element width. The goal here is to make sure that animation is always aplied with the same speed.
private void button_Click(object sender, RoutedEventArgs e) {
double currentPosition = (button.ActualWidth - button.MinWidth) / (rootGrid.ActualWidth - button.MinWidth);
if (button.Tag is bool && (bool)button.Tag)
button.Tag = false;
else {
currentPosition = 1 - currentPosition;
button.Tag = true;
}
SetAnimationDuration(button, new Duration(TimeSpan.FromSeconds(5 * currentPosition)));
}

WPF,C# I don't understand, Ticker Moving From "From" to"To"

in Code
private void TickerGrid_Loaded(object sender, RoutedEventArgs e)
{
double height = TickerCanvas.ActualHeight - TextBoxMarquee.ActualHeight;
TextBoxMarquee.Margin = new Thickness(0, height / 2, 0, 0);
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -TextBoxMarquee.ActualWidth; // -277
doubleAnimation.To = TickerCanvas.ActualWidth; //524
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
TextBoxMarquee.BeginAnimation(Canvas.RightProperty, doubleAnimation);
}
in Xaml
<Grid x:Name="TickerGrid" Grid.Row="2" Loaded="TickerGrid_Loaded" Background="#2B2F3B" >
<Canvas ClipToBounds="True" Name="TickerCanvas" Background="Transparent">
<TextBlock ClipToBounds="True" Name="TextBoxMarquee" Background="#2B2F3B">
<TextBlock.Inlines>
<Run FontWeight="Bold" Foreground="#55CFE3" FontSize="14" Text="This is WPF Ticker Title." />
<Run FontSize="13" Foreground="#FFFFFF" Text="This is Content text." />
</TextBlock.Inlines>
</TextBlock>
</Canvas>
</Grid>
I did make a ticker, but I do not understand the principle that Canvas moves from "From" to "To".
TextBoxMarquee.BeginAnimation(Canvas.RightProperty, doubleAnimation); is the confusing part.
It does NOT animate the Canvas. It animates the Right Property of the textblock.
Canvas.RightProperty is just an identifier of the property, not a reference to the object that has the property. The call to BeginAnimation is on the TextBoxMarquee so the Right property of the TextBox will be animated.
If this is supposed to be a marquee animation then I'd use two textblocks.
You will find a working sample linked from the article here:
https://social.technet.microsoft.com/wiki/contents/articles/31416.wpf-mvvm-friendly-user-notification.aspx#Marquee
https://gallery.technet.microsoft.com/WPF-User-Notification-MVVM-98940828
The sample has a grid, which will expand to fit the width of whatever container it's in.
There is a canvas in this.
A Canvas does not clip it's content if it's outside of the canvas bounds.
That canvas allows one textblock to be positioned offscreen to the right of the panel and another left of the panel.
The grid is then animated left to right.
Storyboard:
<Window.Resources>
<!-- "To" of this is set in code because of the window resizing -->
<Storyboard x:Key="SBmarquee">
<DoubleAnimation From="0"
Duration="00:00:8"
Storyboard.TargetProperty="X"
Storyboard.TargetName="Xmarquee"
RepeatBehavior="3"/>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="MarqueeContainer"
To="1"/>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="MarqueeContainer"
BeginTime="0:0:20"
Duration="0:0:4" To="0"/>
</Storyboard>
</Window.Resources>
Grid:
<Grid x:Name="MarqueeContainer" VerticalAlignment="Bottom">
<Grid.RenderTransform>
<TranslateTransform x:Name="Xmarquee" X="0"/>
</Grid.RenderTransform>
<Canvas Height="24"
TextBlock.Foreground="Red">
<TextBlock Text="{Binding MarqueeMessage, NotifyOnTargetUpdated=True}" Canvas.Left="0">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard Storyboard="{StaticResource SBmarquee}" />
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<TextBlock Text="{Binding MarqueeMessage}"
Foreground="Red"
Canvas.Left="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type Canvas}}}"/>
</Canvas>
</Grid>
As the leftmost textblock moves off the display, the rightmost appears.
Code in Window_ContentRendered and Window_SizeChanged is used to calculate what the current width of the window is.
private Storyboard SBMarquee;
private DoubleAnimation XAnimation;
private void Window_ContentRendered(object sender, EventArgs e)
{
SBMarquee = this.Resources["SBmarquee"] as Storyboard;
XAnimation = SBMarquee.Children[0] as DoubleAnimation;
XAnimation.To = MarqueeContainer.ActualWidth * -1;
this.SizeChanged += Window_SizeChanged;
}
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
XAnimation.To = MarqueeContainer.ActualWidth * -1;
MarqueeContainer.Visibility = Visibility.Hidden;
SBMarquee.Begin();
MarqueeContainer.Visibility = Visibility.Visible;
}
The animation is stopped and re-started by telling it to begin again. This is the simplest way to avoid weirdness as the user resizes.
I hope that's clear.

Cannot reset visual state of Grid in LongListSelector after SelectionChanged event

I implemented VisualStateManager to highlight a selected item in LongListSelector.
The selected item is highlighted during the SelectionChanged event, but the problem is when the event is executed completely, the selected item is still highlighted. Even if I navigate away from the page and get back to the original page, the item is still highlighted. If I add selector.SelectedItem = null; at the end of the SelectionChanged event, it goes through the method again until it finally throws a Object reference not set to instance of an object exception.
How exactly do I reset the visual state of the selected item to Normal once it's out of use ?
SelectionChanged event:
private async void POIS_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
List<CustomUserControl> userControlList = new List<CustomUserControl>();
GetItemsRecursive<CustomUserControl>(PoiLongListSelector, ref userControlList);
//seleted
if(e.AddedItems.Count > 0 && e.AddedItems[0] != null)
{
foreach (CustomUserControl userControl in userControlList)
{
if (e.AddedItems[0].Equals(userControl.DataContext))
{
VisualStateManager.GoToState(userControl, "Selected", true);
}
}
}
//Unselected
if (e.RemovedItems.Count > 0 && e.RemovedItems[0] != null)
{
foreach (CustomUserControl userControl in userControlList)
{
if (e.RemovedItems[0].Equals(userControl.DataContext))
{
VisualStateManager.GoToState(userControl, "Normal", true);
}
}
}
LongListSelector selector = sender as LongListSelector;
PoiData ld = selector.SelectedItem as PoiData;
string navigateUrl = "";
SystemTray.ProgressIndicator = new ProgressIndicator();
SetProgressIndicator(true);
//CHECK IF RETURNING NULL
SystemTray.ProgressIndicator.Text = "Getting GPS data";
GeoCoordinate coordinate = await GetLocation(ctsPoi.Token);
if (coordinate != null)
{
string passedUrl = GenerateUrl(coordinate, ld.Type);
if (passedUrl != null)
{
SystemTray.ProgressIndicator.Text = "Getting POI data";
string jsonData = await GetJsonDataFromGoogle(passedUrl, ld.Type);
if (jsonData != null)
{
string url = SerializeJsonData(jsonData, ld.Type);
if (url != null)
{
SystemTray.ProgressIndicator.Text = "Done";
navigateUrl = string.Format("/ViewDirection.xaml?serializedData={0}", url);
}
}
}
}
if(navigateUrl != "")
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri(navigateUrl, UriKind.RelativeOrAbsolute));
}
CustomUserControl which has the VisualStateManager xaml:
<Grid x:Name="LayoutRoot">
<Grid Margin="0,0,0,15" Grid.Row="0">
<Grid Name="MainGrid" Opacity="1" Visibility="Visible" >
<Grid.Background>
<SolidColorBrush>
<Color>#ff00bfff</Color>
</SolidColorBrush>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Background="{StaticResource PhoneAccentBrush}" Grid.Column="0" Width="65" HorizontalAlignment="Left"
Height="65" Margin="0, 0, 0, 0">
</Grid>
<Grid Grid.Column="1">
<TextBlock Text="{Binding Title}"
FontSize="30" Margin="10,0,0,0"
VerticalAlignment="Center"
Foreground="White"/>
</Grid>
</Grid>
<ProgressBar x:Name="ATMBar" Visibility="Visible"
Opacity="0"
VerticalAlignment="Center"
Margin="0,0,0,0"
IsIndeterminate="True"
Style="{StaticResource CustomIndeterminateProgressBar}" />
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" To="0.2" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="MainGrid" />
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="ATMBar" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
LongListSelector xaml:
<phone:LongListSelector Name="PoiLongListSelector" Margin="12,-20,0,75"
ItemsSource="{Binding Poi.Items}"
SelectionChanged="POIS_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<myUserControl:CustomUserControl />
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
why don't you try something different to highlight the element?, you can binding a background color property or something like that after the selection changed method, if you are using the mvvm pattern well you should have the INotifypropertyChange, so, it must change this value to some other for do the binding to that property

How to stop an animation WPF?

How to stop an animation so it won't produce Completed event. Here's simple example
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="248" Width="318">
<Grid>
<Border Width="20" Height="20" Background="Red" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave" x:Name="border" />
</Grid>
</Window>
And backing code:
private void Border_MouseEnter(object sender, MouseEventArgs e)
{
var a = new DoubleAnimation { To = 0, Duration = TimeSpan.FromMilliseconds(4000) };
a.Completed += (obj, args) => MessageBox.Show("Boom!");
border.BeginAnimation(Border.OpacityProperty, a);
}
private void Border_MouseLeave(object sender, MouseEventArgs e)
{
border.BeginAnimation(Border.OpacityProperty, null);
border.Opacity = 1;
}
If I move mouse out before rectangle becomes white it still will display popup window after some time. How to prevent this? Let's assume that Border_MouseLeave and Border_MouseEnter methods doesn't know about each other (they can't pass animation instance variable to each other).
you can use this:
<Border Width="20" Height="20" Background="Red" x:Name="border" >
<Border.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard Name="Ali">
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:4" Completed="com" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<StopStoryboard BeginStoryboardName="Ali"/>
</EventTrigger>
</Border.Triggers>
</Border>
and :
private void com(object sender, EventArgs e)
{
MessageBox.Show("boom!");
}
You could use Property or Data Trigger's EnterActions and ExitActions properties or as #Ali said correctly use Begin and Stop storyboard.

Categories