Animation in WPF showing images one by one - wpf

I would like to create something like this
animateit.net/categories.php?cat_id=218&page=11 -
Frog Gets Spider Animated Gif ...
I have a frog image, a tongue image and a bug image separate, but not able to put it in animation using WPF.
Any ideas on how to do it?

If you'd like to animate an image in the code-behind, you'll set it up something like this:
MyImage is where you're displaying the "gif".
FrogImage is the image of just the frog.
TongueImage is the image of the tongue coming out.
BugImage is the image of the frog with the bug.
First, initialize a timer like this, perhaps in 'MainWindow()' or at the global level:
DispatcherTimer tmrBlinkImage = new DispatcherTimer()
{ IsEnabled = false, Interval = TimeSpan.FromMilliseconds(500) };
tmrBlinkImage.Tick += new EventHandler(tmrBlinkImage_Tick);
public int _ImageBlinkIndex = 0;
Then, set up the event handler like this:
private void tmrBlinkImage_Tick(object sender, EventArgs e)
{
try
{
if (null == MyImage)
return;
if (MyImage.IsDisposed)
return;
switch (_ImageBlinkIndex)
{
case 0:
if (MyImage.Source != FrogImage)
MyImage.Source = FrogImage;
_ImageBlinkIndex++;
break;
case 1:
if (MyImage.Source != TongueImage)
MyImage.Source = TongueImage;
_ImageBlinkIndex++;
break;
case 2:
if (MyImage.Source != BugImage)
MyImage.Source = BugImage;
_ImageBlinkIndex = 0;
break;
default:
_ImageBlinkIndex = 0;
break;
}
}
catch (Exception ex)
{
tmrBlinkImage.Stop();
//woops....
}
}
This will cycle through the images and update the frame every half second. Adjust the values as you best see fit.

Related

Scrolling in Sticky Notes

I got the following sticky note example:
If the sticky note has more than 9 rows, the additional rows are not visible.
I'm able to navigate through the note with my arrow keys. If I'm going to scroll with the mouse wheel, it seems to ignore the popup and just changes the page.
Is it possible to activate scrolling for sticky note popups?
Edit:The solution outlined below will soon be available as part of the samples included in the PDFTron SDK download. In the meanwhile, I hope that the below solution helps.
Yes, it is possible to activate scrolling for sticky notes.
The problem is most apparent when using the single page view. It appears to work as expected in continuous mode.
However it is not as simple as setting VerticalScrollVisibility = ScrollBarVisibility.Auto;. There are a few files that need to be modified to get this working.
The good news is that we can get the expected behaviour by modifying the code in the provided samples.
Solution
The solution is to add some handling for the PreviewMouseWheel event coming from the PDFViewWPF class.
In the downloaded samples, the following changes were made to get things running as expected:
Add a method to handle the PreviewMouseWheel event in the NoteHost class (Samples/PDFViewWPFTools/CS/Utilities/NoteHost.cs)
internal void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var originalSource = (UIElement)e.OriginalSource;
if (originalSource.IsDescendantOf(mNoteBorder) && mTextBox.IsFocused)
{
mTextBox.ScrollToVerticalOffset(mTextBox.VerticalOffset - e.Delta);
e.Handled = true;
}
}
Also make sure to add mTextBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; in the NoteHost.CreateNoteAndArrow() method, after the mTextBox object is instantiated (~line 183).
Next, edit the NoteManager class - Samples/PDFViewWPFTools/CS/Utilities/NoteManager.cs - and add a HandlePreviewMouseWheel method. This will internally call the HandlePreviewMouseWheel on each displayed (opened) note and break at the first one where the event gets handled.
internal void HandlePreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
foreach(var note in mActiveNotes)
{
note.Value.HandlePreviewMouseWheel(sender, e);
if(e.Handled)
{
break;
}
}
}
Next, edit the ToolManager class to ensure that the note manager gets a chance to handle the PreviewMouseWheel before attempting a page change. Open Samples/PDFViewWPFTools/CS/ToolManager.cs and navigate to the PDFView_PreviewMouseWheel. The existing method should look like this:
private void PDFView_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (mCurrentTool != null && _IsEnabled)
{
ToolManager.ToolType prev_tm = mCurrentTool.ToolMode;
ToolManager.ToolType next_tm;
while (true)
{
mCurrentTool.PreviewMouseWheelHandler(sender, e);
next_tm = mCurrentTool.NextToolMode;
if (prev_tm != next_tm)
{
mCurrentTool = CreateTool(next_tm, mCurrentTool);
prev_tm = next_tm;
}
else
{
break;
}
}
}
}
Replace it with the below code:
private void PDFView_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (mCurrentTool != null && _IsEnabled)
{
ToolManager.ToolType prev_tm = mCurrentTool.ToolMode;
ToolManager.ToolType next_tm;
while (true)
{
mNoteManager.HandlePreviewMouseWheel(sender, e);
if (!e.Handled)
{
mCurrentTool.PreviewMouseWheelHandler(sender, e);
next_tm = mCurrentTool.NextToolMode;
if (prev_tm != next_tm)
{
mCurrentTool = CreateTool(next_tm, mCurrentTool);
prev_tm = next_tm;
}
else
{
break;
}
}
else
{
break;
}
}
}
}
By doing the above, we are giving the NoteManager a chance to handle the PreviewMouseWheel before doing anything else with it.
Another point to note is that we have to now "do the scrolling" in code, using the mTextBox.ScrollToVerticalOffset method in the NoteHost class.

Stuck in an OnPaint loop with a custom control derived from a panel

I have a custom panel designed to be able to either show a solid background color, a gradient background color, or a picture.
I've overridden both the BackgroundImage property and the OnPaint method like so:
protected override void OnPaint(PaintEventArgs pe){
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
if (this.DrawStyle != DrawStyle.Picture){
base.BackgroundImage = null;
if (this.DrawStyle == DrawStyle.Solid){
using (SolidBrush brush = new SolidBrush(this.PrimaryColor))
pe.Graphics.FillRectangle(brush, rc);
}
else if (this.DrawStyle == DrawStyle.Gradient){
using (LinearGradientBrush brush =
new LinearGradientBrush(
rc, this.PrimaryColor, this.SecondaryColor, this.Angle))
pe.Graphics.FillRectangle(brush, rc);
}
}
else if (this._BGImage != null)
base.BackgroundImage = this._BGImage;
}
public override Image BackgroundImage{
get { return this._BGImage; }
set { this._BGImage = value; }
}
The reason being is that the control must be flexible enough to change the background type (Solid, Gradient or Picture) during run time, so the control holds onto the set background image and presents it when necessary.
I am running into a problem, however.
If I do not set the background image, there is no problem. OnPaint is called about 5 times and then it goes fine.
However, when I DO set the background image, it seems to go crazy, calling OnPaint over and over and over and over and over and over again.
This clearly has something to do with overriding the background image and it's a problem, because it's hanging up and nothing on the panel is getting updated until I change the panel appearance.
So I guess the question I have is why is it getting stuck in this OnPaint loop when I set the background image?
Comment out this:
// base.BackgroundImage = this._BGImage;
It's causing it to recursively paint itself. You should never set properties in a paint routine.
Furthermore, you aren't accomplishing anything by overriding the BackgroundImage, and if you do override the property, that should be the only place where you assign the base.BackgroundImage value. Consider removing that.
I reworked your code to this:
protected override void OnPaintBackground(PaintEventArgs e) {
if (this.DrawStyle == DrawStyle.Picture) {
base.OnPaintBackground(e);
}
}
protected override void OnPaint(PaintEventArgs e) {
Rectangle rc = this.ClientRectangle;
if (this.DrawStyle == DrawStyle.Solid) {
using (SolidBrush brush = new SolidBrush(this.PrimaryColor))
e.Graphics.FillRectangle(brush, rc);
} else if (this.DrawStyle == DrawStyle.Gradient) {
using (LinearGradientBrush brush =
new LinearGradientBrush(
rc, this.PrimaryColor, this.SecondaryColor, this.Angle))
e.Graphics.FillRectangle(brush, rc);
}
base.OnPaint(e);
}
Make sure to add this.DoubleBuffered = true; and this.ResizeRedraw = true; in your panel's constructor to avoid unnecessary flicker.

WP7 TouchPanel Gesture Handling

I got a Problem with the Gesturehandling.
I mostly did it after this Tutorial:
http://www.nickharris.net/2010/11/using-touchpanel-for-gestures-in-windows-phone-7/
This is my Remote.xaml file:
<UserControl x:Class="EnergyRadio.Remote"
....
ManipulationCompleted="StackPanel_ManipulationCompleted">
<Grid x:Name="LayoutRoot" Background="Transparent" >
</Grid>
</UserControl>
And this is Remote.xaml.cs:
public Remote()
{
InitializeComponent();
TouchPanel.EnabledGestures = GestureType.VerticalDrag | GestureType.HorizontalDrag;
}
private void StackPanel_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
//Check if touch Gesture is available
if (TouchPanel.IsGestureAvailable)
{
// Read the gesture so that you can handle the gesture type
GestureSample gesture = TouchPanel.ReadGesture();
switch (gesture.GestureType)
{
case GestureType.VerticalDrag:
MessageBox.Show("vertikal");
break;
case GestureType.HorizontalDrag:
MessageBox.Show("horizontal");
break;
default:
//do something
break;
}
}
}
It doesn't matter how i swipe my finger over the Phone it gives me back horizontal. But this should have been the first step ayway. What i actually need are four directions... that means up, down, right and left.
But i cant find this gesturtypes.. so does anybody has an idea?
it should look like this:
switch (gesture.GestureType)
{
case "GesturType.Up":
MessageBox.Show("Volume Up");
break;
case "GesturType.Down":
MessageBox.Show("Volume Down");
break;
case "GesturType.Right":
MessageBox.Show("Next Channel");
break;
case "GesturType.Left":
MessageBox.Show("Previous Channel");
break;
default:
//do something
break;
}
Thanks.
I use another way of handling gesture.. not the XNA way. you can try the GestureService.GestureListener
for example u like to detect the drag event inside of a rectangle you do this
<Rectangle x:Name="HelloRect">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener DragStarted="DragStarted_EventHandler" DragCompleted="DragCompleted_EventHandler" />
</toolkit:GestureService.GestureListener>
</Rectangle>
Then in the code behind you can have event handlers for the gestures
private void DragStarted_EventHandler(object sender, DragStartedGestureEventArgs e)
{
this.HelloRect.Fill = new SolidColorBrush(Colors.White);
}
private void DragCompleted_EventHandler(object sender, DragCompletedGestureEventArgs e)
{
this.HelloRect.Fill = new SolidColorBrush(Colors.Black);
}
Update: this tutorial is good:
http://windowsphonegeek.com/articles/WP7-GestureService-in-depth--key-concepts-and-API
You might want to check some of the references for what you will be getting for the event params:
http://www.mindscapehq.com/Help/PhoneElements/html/2f4dc2f0-f612-6a89-092e-f65c243caded.htm
and
http://www.mindscapehq.com/Help/PhoneElements/html/96092851-e003-6423-389c-58d16281122b.htm
There is also a drag delta event that you can look into.
Hope it helps in any way.. i am not very familiar with the touch panel thing..sorry about that.. you might want to wait for a few more replies
From the drag start and drag end coordinates you can conclude the direction of drag
..I think you are looking into the flick event.. another good tutorial
http://johnhforrest.com/2010/09/windows-phone-7-gestures/
Update AGAIN:
The FlickGestureEventArgs contains a Direction property which is of type System.Windows.Controls.Orientation http://msdn.microsoft.com/en-us/library/system.windows.controls.orientation.aspx
from there you can determine the direction of flick
private void Flick_EventHandler(object sender, FlickGestureEventArgs e)
{
if (e.Direction == Orientation.Horizontal)
{
if (e.HorizontalVelocity < 0)
{
//Right flick
}
else
{
//Left flick
}
}
else
{
if (e.VerticalVelocity < 0)
{
//Up flick
}
else
{
//Down flick
}
}
}
Good luck and good night..
Update:
I just saw you should not be using switch cases for the GestureType enumeration... they are integer types
for a list of gesture type see
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.input.touch.gesturetype.aspx

Remove images from RichTextBox FlowDocument

I have a WPF application on which the user can paste some data from Word inside a RichTextBox... but if that word data has an image, I need to remove it, how can I accomplish that?
Since the FlowDocument is xml, maybe doing some linq magic could do it, but I don't know how.
There is a tool called WordtoXAML Converter (http://wordtoxaml.codeplex.com). You can use that to convert your Word document contents to XAML, use regular expression matching to identify the images and then strip them out.
The following code will do what you want. While it can be a bit wasteful (it looks through the entire document instead of just the bit that was just pasted), it is the only way to do it, as sometimes the RichTextBox is inaccurate when it indicates the recently painted range:
public class MyTextBox : RichTextBox
{
public MyTextBox()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, Paste));
}
protected virtual void Paste(object sender, ExecutedRoutedEventArgs e)
{
Paste();
foreach (var image in FindImages())
{
if (image.SiblingInlines != null)
{
image.SiblingInlines.Remove(image);
}
}
}
IEnumerable<InlineUIContainer> FindImages()
{
var result = new List<InlineUIContainer>();
var blocks = Document.Blocks;
for (TextPointer position = blocks.FirstBlock.ElementStart; position != null && position.CompareTo(blocks.LastBlock.ElementEnd) != 1; position = position.GetNextContextPosition(LogicalDirection.Forward))
{
InlineUIContainer element = position.Parent as InlineUIContainer;
if (element != null && element.Child is Image)
{
result.Add(element);
}
}
return result;
}
}

Memory Leak in WPF

I wrote a very simple newbie app with a 6-sided polyhedron (a "box") which rotates 180 degrees when I click a button. and then rotates back again on the next click. Every rotation grabs another 90MB and it doesn't let go until I close the app. The box is defined in the XAML. The Storyboard, DoubleAnimation and PropertyPath, etc, are all created ONCE, in the constructor. The button code looks like this:
private void button_Storyboard1_Click(object sender, RoutedEventArgs e)
{
GC.Collect();
if (_bFront)
{
_myDoubleAnimation.From = 0;
_myDoubleAnimation.To = 180;
_bFront = false;
}
else
{
_myDoubleAnimation.From = 180;
_myDoubleAnimation.To = 0;
_bFront = true;
}
_myDoubleAnimation.Duration = _Duration;
Storyboard.SetTargetName(_myDoubleAnimation, "rotate_me");
Storyboard.SetTargetProperty(_myDoubleAnimation, _PropP);
_sb.Children.Add(_myDoubleAnimation);
_sb.Begin(this.viewport3D1);
}
After a few rotations I'm out of memory! What's going on?
Could be totally wrong here, but aren't you adding _myDoubleAnimation to _sb.Children on each click, instead of just updating it?

Resources