I'm making a WPF application using C# and Visual Studio and I need a button to jump to a random location in the window when the mouse hovers over it. I then need the same thing to happen when you hover over it again. I also don't need an animation, just for it to jump there.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void butNo_MouseEnter(object sender, MouseEventArgs e)
{
}
}
I tried this but it didn't work and is also an animation:
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="100" Duration="0:0:2" Storyboard.TargetProperty="(Canvas.Left)" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
Any help would be much appreciated, thanks.
Edit:
Tried this but 'Location' comes with error code CS1061 in VS.
private void butNo_MouseEnter(object sender, MouseEventArgs e)
{
Random x = new Random();
Point pt = new Point(int.Parse(x.Next(200).ToString()), int.Parse(x.Next(250).ToString()));
butNo.Location = pt;
}
Here's a solution using a Canvas and animations.
<Canvas Name="cnv">
<Button Name="btn"
Content="Click Me!"
IsTabStop="False"
Canvas.Left="0"
Canvas.Top="0"
MouseEnter="Button_MouseEnter"/>
</Canvas>
And the code-behind:
Random rnd = new Random();
private void Button_MouseEnter(object sender, MouseEventArgs e)
{
//Work out where the button is going to move to.
double newLeft = rnd.Next(Convert.ToInt32(cnv.ActualWidth - btn.ActualWidth));
double newTop = rnd.Next(Convert.ToInt32(cnv.ActualHeight - btn.ActualHeight));
//Create the animations for left and top
DoubleAnimation animLeft = new DoubleAnimation(Canvas.GetLeft(btn), newLeft, new Duration(TimeSpan.FromSeconds(1)));
DoubleAnimation animTop = new DoubleAnimation(Canvas.GetTop(btn), newTop, new Duration(TimeSpan.FromSeconds(1)));
//Set an easing function so the button will quickly move away, then slow down
//as it reaches its destination.
animLeft.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
animTop.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
//Start the animation.
btn.BeginAnimation(Canvas.LeftProperty, animLeft, HandoffBehavior.SnapshotAndReplace);
btn.BeginAnimation(Canvas.TopProperty, animTop, HandoffBehavior.SnapshotAndReplace);
}
And here is a gif of it in action.
I really don't normally like doing homework problems for people, but I'm bored at work so here you go.
You need to just use the Margin and update the Left and Top values to random numbers within the height/width of your grid so it doesn't go outside of the view.
Also, make sure to use IsTabStop="False" otherwise, you could tab to it and still click it.
So, for the simplest case using codebehind:
XAML:
<Window x:Class="mousemove.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="Grid1">
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="button1" Width="75" MouseEnter="button1_MouseEnter" IsTabStop="False"/>
</Grid>
MainWindow.xaml.cs
private void button1_MouseEnter(object sender, MouseEventArgs e)
{
int maxLeft = Convert.ToInt32(Grid1.ActualWidth - button1.Width);
int maxTop = Convert.ToInt32(Grid1.ActualHeight - button1.Height);
Random rand = new Random();
button1.Margin = new Thickness(rand.Next(maxLeft), rand.Next(maxTop), 0, 0);
}
Related
I have this code. This is just an example. I want to do it with code. How to animate the Foreground property of multiple "Run" elements in a TextBlock?
<Page
x:Class="AnimationTest.MainPage"
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:local="using:AnimationTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<TextBlock
x:Name="_textBlockElement"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="72"><Run x:Name="_run1" Text="Hel" /><Run Text="lo" />
<TextBlock.Triggers>
<EventTrigger>
<BeginStoryboard>
<Storyboard x:Name="ColorStoryboard">
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetName="_textBlockElement"
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>
</Page>
Oke, so this took quite some sorting out, but turned out to be quite doable.
The key is to create two storyboards in code behind with the correct animations and then add those storyboards to the resources of any parent of the Run's.
Let's start of with the XAML code, which is pretty simple:
<Grid>
<TextBlock x:Name="TestBlock"
HorizontalAlignment="Center" VerticalAlignment="Center"
PointerEntered="TestBlock_PointerEntered"
PointerExited="TestBlock_PointerExited">
<Run x:Name="Run1" Text="Test1" Foreground="Blue"/>
<Run x:Name="Run2" Text="Test2" Foreground="Green"/>
<!-- ... -->
</TextBlock>
</Grid>
For simplicity I have already defined the names and foregrounds of the Run's.
Now we need to define the storyboards and animations in code behind.
I've chosen to do this in the constructor (after InitializeComponent()!). In theory you should be able to also paste this code in the Page_Loaded event.
public MainPage()
{
InitializeComponent();
SetupStoryBoards();
}
void SetupStoryBoards()
{
// Define duration and storyboards to red and original color
var duration = new Duration(TimeSpan.FromSeconds(1));
var toRedStory = new Storyboard { Duration = duration };
// completed events can be subscribed to, to register when animation is done
//toRedStory.Completed += Story_Completed;
var toOriginalStory = new Storyboard { Duration = duration };
//toOriginalStory.Completed += ToOriginalStory_Completed;
foreach (Run r in TestBlock.Inlines)
{
// Filter out any inlines that are not a named Run
if (string.IsNullOrEmpty(r.Name))
continue;
// Define the animations
var toRedAnim = new ColorAnimation
{
Duration = duration,
To = Colors.Red,
EnableDependentAnimation = true
};
var toOriginalAnim = new ColorAnimation
{
Duration = duration,
To = (r.Foreground as SolidColorBrush).Color, // Causes animation to go back to original foreground color of Run
EnableDependentAnimation = true
};
// Add animations to the storyboards and associate animations with the Run
toRedStory.Children.Add(toRedAnim);
toOriginalStory.Children.Add(toOriginalAnim);
Storyboard.SetTargetName(toRedAnim, r.Name);
Storyboard.SetTargetName(toOriginalAnim, r.Name);
Storyboard.SetTargetProperty(toRedAnim, "(Run.Foreground).(SolidColorBrush.Color)");
Storyboard.SetTargetProperty(toOriginalAnim, "(Run.Foreground).(SolidColorBrush.Color)");
}
// Add the storyboards to the resources of any parent of the Run's for easy retrieval later and to make the animations find the Run's
// I choose the resources of the textblock that contains the Run's
TestBlock.Resources.Add("toRedStory", toRedStory);
TestBlock.Resources.Add("toOriginalStory", toOriginalStory);
}
Now to execute the animations, we add the PointerEntered and PointerExited eventhandlers, and begin the correct storyboards there:
private void TextBlock_PointerEntered(object sender, PointerRoutedEventArgs e)
{
var story = TestBlock.Resources["toRedStory"] as Storyboard;
story.Begin();
}
private void TextBlock_PointerExited(object sender, PointerRoutedEventArgs e)
{
var story = TestBlock.Resources["toOriginalStory"] as Storyboard;
story.Begin();
}
You should be able to extend this wherever needed, however I have found that EnableDependentAnimation must be set to true since otherwise it won't work.
I am trying to make a WPF application using the MVVM pattern.
I now want to be able to navigate between ViewModels, and for that I've used this article: https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
Basically, the Main Window Resources contain DataTemplates for each View Model linking it to it's view, and a Content Control bound to CurrentPageViewModel like this:
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:VaultViewModel}">
<Views:VaultView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:VaultsViewModel}">
<Views:VaultsView />
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentPageViewModel}" />
In the constructor of the Main Window I set CurrentPageViewModel to a new instance of my home screen view model and when I want to navigate, all I need to do is change CurrentPageViewModel and WPF will do the rest because of my use of INotifyPropertyChanged.
I am sending Change Page requests to the main window from my View Models by copying the code from MVVM Light's messenger implementing the Mediator pattern, and this works fine, except when I have Storyboards playing.
I have two very nice buttons inside of my home page, which will grow a bit when you hover over them:
<Button Style="{DynamicResource MaterialButton}" Width="400px" Height="400px" Margin="15px"
FontSize="24" FontFamily="Roboto" FontWeight="Bold"
Effect="{DynamicResource HomeButtonDropShadowEffect}" Command="{Binding DisplayVaultsView}"
Content="Vaults">
<!--#region button effects -->
<Button.RenderTransform>
<ScaleTransform x:Name="scaleTransform" CenterX="200" CenterY="200" ScaleX="1.0" ScaleY="1.0"/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX"
To="1.08" Duration="0:0:0.1"/>
<DoubleAnimation
Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleY"
To="1.08" Duration="0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX"
To="1.0" Duration="0:0:0.1" FillBehavior="Stop"/>
<DoubleAnimation
Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleY"
To="1.0" Duration="0:0:0.1" FillBehavior="Stop"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
<!--#endregion-->
</Button>
As you can see, the button's Command is set to DisplayVaultsView, which is a method inside of the HomeViewModel which sends the Change Page request to the Main Window.
Without these storyboards inside the button, this works just fine and the new page is displayed. However, with the storyboards, the following error is thrown once I click the button:
System.InvalidOperationException: ''scaleTransform' name cannot be found in the name scope of 'System.Windows.Controls.Button'.'
This has led me to believe that the animation is still attempting to play, but since the Button is not in the current context anymore it can't find the property it's supposed to animate.
It's also important to note that the HomeViewModel is not thrown away when you navigate to another page, I've written my own Navigator class which keeps track of the ViewModels so you can navigate forwards/backwards without losing any changes (and without having to reload everything).
I'd like to know how I can solve this error, but it has also led me to the realization that I might need to "unload" ViewModels when switching to another one. I'm currently just keeping all ViewModel references inside of a List inside the Navigator class. So my other question is, should I "unload" the ViewModels when switching to another, and how?
I found a solution which works, but I'm not sure as to why it worked.
I removed all of the XAML concerned with the animations, and moved the animating to the code-behind in HomeView.xaml.
Here's the code:
public partial class HomeView : UserControl
{
private Storyboard _mouseEnterStoryboard;
private Storyboard _mouseLeaveStoryboard;
private DoubleAnimation _scaleX_In;
private DoubleAnimation _scaleY_In;
private DoubleAnimation _scaleX_Out;
private DoubleAnimation _scaleY_Out;
public HomeView()
{
InitializeComponent();
_mouseEnterStoryboard = new Storyboard();
ScaleTransform scaleVaultsButton = new ScaleTransform(1.0, 1.0);
ScaleTransform scaleFilesButton = new ScaleTransform(1.0, 1.0);
VaultsButton.RenderTransformOrigin = new Point(0.5, 0.5);
VaultsButton.RenderTransform = scaleVaultsButton;
FilesButton.RenderTransformOrigin = new Point(0.5, 0.5);
FilesButton.RenderTransform = scaleFilesButton;
_scaleX_In = new DoubleAnimation()
{
Duration = TimeSpan.FromMilliseconds(100),
From = 1.0,
To = 1.08
};
_scaleY_In = new DoubleAnimation()
{
Duration = TimeSpan.FromMilliseconds(100),
From = 1.0,
To = 1.08
};
_mouseEnterStoryboard.Children.Add(_scaleX_In);
_mouseEnterStoryboard.Children.Add(_scaleY_In);
Storyboard.SetTargetProperty(_scaleX_In, new PropertyPath("RenderTransform.ScaleX"));
Storyboard.SetTargetProperty(_scaleY_In, new PropertyPath("RenderTransform.ScaleY"));
_mouseLeaveStoryboard = new Storyboard();
_scaleX_Out = new DoubleAnimation()
{
Duration = TimeSpan.FromMilliseconds(100),
From = 1.08,
To = 1.0
};
_scaleY_Out = new DoubleAnimation()
{
Duration = TimeSpan.FromMilliseconds(100),
From = 1.08,
To = 1.0
};
_mouseLeaveStoryboard.Children.Add(_scaleX_Out);
_mouseLeaveStoryboard.Children.Add(_scaleY_Out);
Storyboard.SetTargetProperty(_scaleX_Out, new PropertyPath("RenderTransform.ScaleX"));
Storyboard.SetTargetProperty(_scaleY_Out, new PropertyPath("RenderTransform.ScaleY"));
VaultsButton.MouseEnter += new MouseEventHandler(Button_MouseEnter);
VaultsButton.MouseLeave += new MouseEventHandler(Button_MouseLeave);
FilesButton.MouseEnter += new MouseEventHandler(Button_MouseEnter);
FilesButton.MouseLeave += new MouseEventHandler(Button_MouseLeave);
}
public void Button_MouseEnter(object sender, MouseEventArgs e)
{
Storyboard.SetTarget(_scaleX_In, (Button)sender);
Storyboard.SetTarget(_scaleY_In, (Button)sender);
_mouseEnterStoryboard.Begin();
}
public void Button_MouseLeave(object sender, MouseEventArgs e)
{
Storyboard.SetTarget(_scaleX_Out, (Button)sender);
Storyboard.SetTarget(_scaleY_Out, (Button)sender);
_mouseLeaveStoryboard.Begin();
}
}
I'm not sure as to why this does work and the XAML version doesn't, so I'd still like an answer to that question.
I would like to play video on top of the current window. Another video is playing in the background of the current window.
I'm using MMVM and Microsoft's Microsoft.Practices.Unity in my WPF project. I have added a Canvas and in code behind using MediaPlayer, VideoDrawing, DrawingBrush to show the player Canvas and play video.
Most of the time it works perfectly but sometime it stops playing video and shows a blank screen.
Expected :
Unexpected :
UserControl
<UserControl x:Class="VideoDemo.Views.SampleView"
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"
xmlns:local="clr-namespace:VideoDemo.Views"
mc:Ignorable="d"
>
<StackPanel Orientation="Horizontal">
<Canvas x:Name="MainCanvas" Width="540" Height="340">
<MediaElement Width="540" Height="340" Stretch="Fill">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<MediaTimeline x:Name="bgVideo" Source="BGLoop.mp4" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
<Button Content="Show Popup" Foreground="Black" Click="Button_Click" ></Button>
<!--Video Player-->
<Canvas Name="canvasPlayer" Width="540" Height="292"
Margin="0"
VerticalAlignment="Top"
>
</Canvas>
</Canvas>
</StackPanel>
Button Click
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Canvas.SetZIndex(canvasPlayer, 99);
bool isMediaClosed = false;
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(10);
MediaPlayer mp = new MediaPlayer();
var bgVideoPath = Environment.CurrentDirectory + #"\Touchdown.mp4";
mp.Open(new Uri(bgVideoPath));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 100, 100);
DrawingBrush db = new DrawingBrush(vd);
var btnBg = MainCanvas.Background;
// Affect the drawing brush as a background for all 9 buttons
//foreach (Button b in videoGrid.Children)
canvasPlayer.Background = db;
// Lecture!
mp.Play();
timer.Start();
//Timer to remove the blank screen. Otherwise whole time blank screen sticked
timer.Tick += (t, l) =>
{
timer.Stop();
if (!isMediaClosed)
{
mp.Stop();
mp.Close();
canvasPlayer.Background = btnBg;
Canvas.SetZIndex(canvasPlayer, -1);
isMediaClosed = true;
}
};
mp.MediaEnded += (k, p) =>
{
mp.Stop();
mp.Close();
canvasPlayer.Background = btnBg;
Canvas.SetZIndex(canvasPlayer, -1);
isMediaClosed = true;
};
}
catch (Exception)
{
}
}
FOR THOSE WHO CAN DOWNLOAD AND CHECK MY CODE. I have written an sample application for this and you can download it from here. I have tried to re generate this issue in this demo app but not got.
I have these two animations here, one to close a slide out grid navigation menu, and the other to set a rectangles fill to transparent as that menu closes.
I would like these to both happen at the same time. Right now the animations happen in the order they are invoked.
How can I implement this as simple and clean as possible using C# code? I am only creating this application to learn about animations and different ways layout controls.
private void _CloseSlideGrid()
{
DoubleAnimation da = new DoubleAnimation();
da.Duration = TimeSpan.FromSeconds(0.3d);
da.DecelerationRatio = 1.0d;
da.From = 500.0d;
da.To = 0.0d;
_slideGrid.BeginAnimation(Grid.WidthProperty, da);
}
private void _DisableTransparentCover()
{
BrushAnimation ba = new BrushAnimation();
ba.Duration = TimeSpan.FromSeconds(0.3d);
ba.DecelerationRatio = 1.0d;
ba.From = _GetBrush("#77000000");
ba.To = _GetBrush("#00000000");
_tranparentCover.BeginAnimation(Rectangle.FillProperty, ba);
}
An event callback for my close button invokes my two private functions that will handle the animations.
private void _NavCloseButton_Click(object sender, RoutedEventArgs e)
{
_CloseSlideGrid();
_DisableTransparentCover();
}
Here is a link to an Imgur album with a screenshot of the two states of my window, if you are intrested:
http://imgur.com/a/ZaSr1
Let me know if I can provide any more information,
Thanks.
Just add them on the same storyboard and it should be fine. I'm not sure what your BrushAnimation is but using ColorAnimation with the property path as below is working just fine.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
SizeToContent="WidthAndHeight">
<Window.Resources>
<Storyboard x:Key="CloseAnimation">
<DoubleAnimation From="500.0" To="0.0" DecelerationRatio="1.0" Duration="00:00:03"
Storyboard.TargetName="MyTextBox" Storyboard.TargetProperty="Width"/>
<ColorAnimation From="#77000000" To="#00000000" DecelerationRatio="1.0" Duration="00:00:03"
Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"/>
</Storyboard>
</Window.Resources>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox x:Name="MyTextBox" Grid.Column="0" Width="500"/>
<Grid x:Name="MyGrid" Grid.Column="1" Background="#77000000" Width="100"/>
</Grid>
<Button Content="Animate">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click" >
<BeginStoryboard Storyboard="{StaticResource CloseAnimation}"/>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Window>
If you REALLY want to do this in code behind and have no other way around it translates as such.
private void _CloseSlideGrid(Storyboard sb)
{
DoubleAnimation da = new DoubleAnimation();
da.Duration = TimeSpan.FromSeconds(0.3d);
da.DecelerationRatio = 1.0d;
da.From = 500.0d;
da.To = 0.0d;
Storyboard.SetTarget(da, MyTextBox);
Storyboard.SetTargetProperty(da, new PropertyPath("Width"));
sb.Children.Add(da);
}
private void _DisableTransparentCover(Storyboard sb)
{
ColorAnimation ba = new ColorAnimation();
ba.Duration = TimeSpan.FromSeconds(0.3d);
ba.DecelerationRatio = 1.0d;
ba.From = (Color)ColorConverter.ConvertFromString("#77000000");
ba.To = (Color)ColorConverter.ConvertFromString("#00000000");
Storyboard.SetTarget(ba, MyGrid);
Storyboard.SetTargetProperty(ba, new PropertyPath("(Background).(SolidColorBrush.Color)"));
sb.Children.Add(ba);
}
private void _NavCloseButton_Click(object sender, RoutedEventArgs e)
{
var sb = new Storyboard();
_CloseSlideGrid(sb);
_DisableTransparentCover(sb);
sb.Begin();
}
I've been teaching myself WPF through Sells/Griffiths' "Programming WPF", and I've found it a great resource, but I'm trying to take some of the concepts they've introduced me to and go a step further, and I'm running into a conceptual snag on how to put the pieces together to accomplish what I'm trying to do.
In this exercise, I'm trying to create self-terminating animations; FrameworkElements that are created by Events, perform an animation, and then delete themselves. I'm having problems figuring out how to call back to the parent FrameworkElement from the animation.Completed event.
I asked this question originally just using DoubleAnimations that were uncontained and not part of the Storyboard. I have since added the Storyboard, and made the Storyboard and rectangle resources so they can be reused easily.
Here's what I have so far:
.xaml:
<Window.Resources>
<Storyboard x:Key="GrowSquare" x:Shared="False">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="-50" Duration="0:0:2"/>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="-50" Duration="0:0:2"/>
<DoubleAnimation Storyboard.TargetProperty="(Ellipse.Width)" By="100" Duration="0:0:2"/>
<DoubleAnimation Storyboard.TargetProperty="(Ellipse.Height)" By="100" Duration="0:0:2"/>
</Storyboard>
<Rectangle x:Key="MyRect" x:Shared="False" Width="20" Height="20">
</Rectangle>
</Window.Resources>
<Canvas x:Name="myCanvas" MouseMove="myCanvas_MouseMove" Background="White"/>
.cs:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
lastFire = DateTime.Now;
}
DateTime lastFire;
private void myCanvas_MouseMove(object sender, MouseEventArgs e)
{
DateTime nowTime = DateTime.Now;
TimeSpan T = nowTime.Subtract(lastFire);
if (T.TotalMilliseconds > 200)
{
lastFire = nowTime;
Random Rand = new Random();
Rectangle myRect = (Rectangle)FindResource("MyRect");
myRect.Fill = new SolidColorBrush(Color.FromRgb((byte)Rand.Next(256), (byte)Rand.Next(256), (byte)Rand.Next(256)));
Point myLoc = e.GetPosition(myCanvas);
Canvas.SetLeft(myRect, myLoc.X - 10);
Canvas.SetTop(myRect, myLoc.Y - 10);
myCanvas.Children.Add(myRect);
Storyboard SB = (Storyboard)FindResource("GrowSquare");
SB.Completed += new EventHandler(SB_Completed);
SB.Begin(myRect);
}
}
void SB_Completed(object sender, EventArgs e)
{
myCanvas.Children.RemoveAt(0);
}
}
This works, but not in the way I'd like it. Since the canvas is empty, and all animations are the same length, when an animation finishes, it will always be the one that was called on the first child of the canvas.
However, I'd like to implement animaitons that take a random amount of time, meaning that animations will not always start and end in the same order. Somehow in the SB_Completed event, I'd like to access the control that it was being called upon, but I can't seem to find the path to it yet.
Is there a way to get from the Media.Animation.ClockGroup that calls the SB_Completed event to the control that the animation is being called on?
change the line where you assign the event handler to this:
SB.Completed += (s,e) => myCanvas.Children.Remove(myRect);