After playing a MediaElement, how can I play it again? - wpf

I have a variable MediaElement variable named TestAudio in my Silverlight app.
When I click the button, it plays the audio correctly.
But when I click the button again, it does not play the audio.
How can I make the MediaElement play a second time?
None of the tries below to put position back to 0 worked:
private void Button_Click_PlayTest(object sender, RoutedEventArgs e)
{
//TestAudio.Position = new TimeSpan(0, 0, 0);
//TestAudio.Position = TestAudio.Position.Add(new TimeSpan(0, 0, 0));
//TestAudio.Position = new TimeSpan(0, 0, 0, 0, 0);
//TestAudio.Position = TimeSpan.Zero;
TestAudio.Play();
}

I found it, you just have to stop the audio first, then set the position:
TestAudio.Stop();
TestAudio.Position = TimeSpan.Zero;

The MediaElement has no built-in support for looping playback. You can use the MediaEnded event and simply set the media position to zero or you can call the Stop() method. Either one will put you at the beginning of your video/audio for playback.
public partial class MainPage : UserControl
{
public MainPage()
{
// Required to initialize variables
InitializeComponent();
// Used for loopback.
MyME.MediaEnded += new RoutedEventHandler(MyME_MediaEnded);
}
// MediaElement has no looping capabilities so need to set the position back
// to the begining after the video finishes in order to play again.
// Or you can use the stop method
void MyME_MediaEnded(object sender, RoutedEventArgs e)
{
//MyME.Position = TimeSpan.Zero;
MyME.Stop();
}
private void BtnPlay_Click(object sender, RoutedEventArgs e)
{
MyME.Play();
}
private void BtnPause_Click(object sender, RoutedEventArgs e)
{
MyME.Pause();
}
private void BtnStop_Click(object sender, RoutedEventArgs e)
{
MyME.Stop();
}
}

I found the above did not work for me, and the only way I could get it working was to create a mediaelement dynamically. Heres the code I used - I copied the values from a MediaElement named mePlayClick I initially put in the XAML but you may not need to do this.
private void Play_MediaSound()
{
// Create new media element dynamically
MediaElement mediaElement = new MediaElement();
// Reuse settings in XAML
mediaElement.Volume = mePlayClick.Volume;
mediaElement.Source = mePlayClick.Source;
mediaElement.AutoPlay = mePlayClick.AutoPlay;
// WHen the media ends, remove the media element
mediaElement.MediaEnded += (sender, args) =>
{
LayoutRoot.Children.Remove(mediaElement);
mediaElement = null;
};
// Add the media element, must be in visual ui tree
LayoutRoot.Children.Add(mediaElement);
// When opened, play
mediaElement.MediaOpened += (sender, args) =>
{
mediaElement.Play();
};
}

Related

WinForms - WPF like painting

We know very well how easy is too create a WPF application where user can paint a rectangle using the mouse. To do this you just create a Rectangle control and set its coordinates, you don't worry about DoubleBuffering, repainting and such stuff. Well, I'd be very happy yo use WPF for the application where user can paint different shapes, but the clients insists to be a WinForms application. So the solution here is to use the XOR or ROP operation like in old good WinAPI years and I don't really like this. This doesn't give me a nice option to move a text while in XOR mode.
So I was thinking how can I achieve same smooth painting experience in a WinForms application like I'd have in WPF. Put together such a code, where I wanted to create a separate layer where I'd paint the current shape, while leaving intact the rest of the objects. I used same technique in an iPad application and worked pretty well.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace TestPainting
{
public partial class Form1 : Form
{
private bool _isMouseDown;
private Graphics _bufferGraphics;
private Point _startPos;
private TransparentPanel _paintBuffer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
_isMouseDown = true;
_paintBuffer = new TransparentPanel
{
Size = Size,
};
Controls.Add(_paintBuffer);
_paintBuffer.BringToFront();
_bufferGraphics = Graphics.FromHwnd(_paintBuffer.Handle);
_startPos = e.Location;
Capture = true;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!_isMouseDown)
return;
_bufferGraphics.Clear(Color.Transparent);
_bufferGraphics.DrawRectangle(Pens.Green, _startPos.X, _startPos.Y, e.X - _startPos.X, e.Y - _startPos.Y);
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
_isMouseDown = false;
Capture = false;
_bufferGraphics.Dispose();
Controls.Remove(_paintBuffer);
_paintBuffer.Dispose();
}
}
public class TransparentPanel : Panel
{
public TransparentPanel()
{
DoubleBuffered = true;
}
[Browsable(false)]
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do Nothing
}
}
}
which if course doesn't work as needed. I'm getting a black panel when pressing the mouse instead of a transparent one. Plus the rectangle while is painted flickers a lot, even though I did set the DoubleBuffering stuff.
Can someone provide some better ideas of such an implementation or maybe there some other open source project where I can see how other people are doing. I'd need to have same experience as in Paint.NET, just too bad is not open source anymore. (I know I can use Reflector, and I did, but man, there is tons of code over there :) )
Thx for any ideas.
Try this (see FIX #1 and FIX #2):
private void Form1_MouseDown( object sender, MouseEventArgs e )
{
_isMouseDown = true;
_paintBuffer = new TransparentPanel
{
Size = Size,
};
Controls.Add( _paintBuffer );
_paintBuffer.BringToFront();
// FIX #1:
//
this.Refresh();
_bufferGraphics = Graphics.FromHwnd( _paintBuffer.Handle );
_startPos = e.Location;
Capture = true;
}
private void Form1_MouseMove( object sender, MouseEventArgs e )
{
if ( !_isMouseDown )
return;
//FIX #2:
// _bufferGraphics.Clear( Color.Transparent );
_bufferGraphics.Clear( this.BackColor );
_bufferGraphics.DrawRectangle( Pens.Green, _startPos.X, _startPos.Y, e.X - _startPos.X, e.Y - _startPos.Y );
}

Get target control from DoubleAnimation Completed event in WPF?

I'm hoping someone can help me with what I thought would be a relatively straight forward problem.
I am setting a fadeout animation in code using a DoubleAnimation object. It fades out an image, and then fires off the Completed event when it's done.
I would like to get the name of the control that the fadeout animation was applied to from within the event handler, but I can't find a way.
Any help appreciated. Thanks.
DispatcherTimer timer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
image1.Visibility = System.Windows.Visibility.Visible;
image2.Visibility = System.Windows.Visibility.Collapsed;
timer.Interval = TimeSpan.FromSeconds(2);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void FadeOut(UIElement element)
{
DoubleAnimation FadeOut = new DoubleAnimation(1, 0, new Duration(TimeSpan.FromSeconds(0.5)));
FadeOut.Completed += new EventHandler(FadeOut_Completed);
element.BeginAnimation(OpacityProperty, FadeOut);
}
void FadeOut_Completed(object sender, EventArgs e)
{
// How to find out which control was targeted?
}
void timer_Tick(object sender, EventArgs e)
{
if (image1.Visibility == System.Windows.Visibility.Visible)
{
FadeOut(image1);
//image1.Visibility = System.Windows.Visibility.Collapsed;
//image2.Visibility = System.Windows.Visibility.Visible;
}
}
The following code gives you the target of completed animation. Place it in FadeOut_Completed() handler:
DependencyObject target = Storyboard.GetTarget(((sender as AnimationClock).Timeline as AnimationTimeline))
However this will only work if animation target object is specified. To do it add the following to FadeOut() method:
Storyboard.SetTarget(FadeOut, element);

Why does Image not appear when rendering it before?

Starting with a newly created project I add a button to my main page and do the following in the click handler:
I create an Image and assign a BitmapImage as its Source. Then I add the Image to my LayoutRoot. My expectation is that I see the image in the GUI after I click the button.
Now there is the twist: I also want to render this Image to a WriteableBitmap. Therefore I create such a bitmap and call its Render method to render the image.
Here is the problem: when I comment out the Render call then I immediately see the Image appear on my main page. When I include the Render call, then the Image appears not on the first button click, but on the second. Why?
Here is the code:
private void button1_Click(object sender, RoutedEventArgs e)
{
WriteableBitmap wbmp = new WriteableBitmap(62, 62);
BitmapImage bmp = new BitmapImage(new Uri("ApplicationIcon.png", UriKind.Relative));
Image img = new Image() { Width = 62, Height = 62, Source = bmp };
wbmp.Render(img, null); // <------ this line makes the difference
LayoutRoot.Children.Add(img);
}
There are some remarks of using Render (may be one of these makes your issue):
After calling this method, you must call Invalidate in order to render
the bitmap.
This method does support UIElement objects that are not part of the
visual tree. You are required to call Measure and Arrange for
UIElement objects that are not in the visual tree, before calling
Render.
try this..
private Image _img = new Image ();
public Image img
{
get
{
return _img;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String PropertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
WriteableBitmap wbmp = new WriteableBitmap(62, 62);
BitmapImage bmp = new BitmapImage(new Uri("ApplicationIcon.png", UriKind.Relative));
Image img = new Image() { Width = 62, Height = 62, Source = bmp };
wbmp.Render(img, null); // <------ this line makes the difference
LayoutRoot.Children.Add(img);
NotifyPropertyChanged("Image");
}
this should work.. try once...

Silverlight 4:How to delay Mouseenter event

i have a situation where : User moves mouse over the image .
If user keeps mouse on that image for specific time ex. 2 seconds then only i have to proceed
further in mouseenter event otherwise don't.
I have already refred to http://forums.silverlight.net/t/86671.aspx/1 but looks like mine is different case.
One option is to use a DispatchTimer to determine the length of the mouse over.
bool isMouseOverImage = false;
public void Image_MouseEnter(object sender, MouseEventArgs e)
{
this.isMouseOverImage = true;
var timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(2);
timer.Tick += (object timerSender, EventArgs timerArgs) =>
{
if(this.isMouseOverImage)
{
// write your code
}
// stop the timer
timer.Stop();
};
timer.Start();
}
public void Image_MouseLeave(object sender, MouseEventArgs e)
{
this.isMouseOverImage = false;
}
If you have multiple images, you should create a re-usable Behavior and attach it to each image. I can define code for that if that would help.

WPF Threading Grab Bag

I have developed an interesting WPF control that is currently slowing down my entire application :) On my custom control, I have an image control that I need to update everytime a backend event occurs. This backend event is firing twice a second (very fast). When the event fires I need to pull a Bitmap object out of a 3rd party control, convert to a BitmapSource object and then bind it to my Image control. Each time my event is fired, I am queuing a new work item in the ThreadPool. The item will then fetch the Bitmap and do the conversion in a background worker object. This is done everytime the event fires. I am using the dispatcher to update my image control source with BeginInvoke but I still get an unresponsive app. Please let me know what I can do to make this process better performing and help to make my app more responsive:
Here is the code in my event:
void inSight_ResultsChanged(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEvent), ((InSightViewer)this.DataContext).CvsDisplay);
}
Here is the code from delegate:
void ProcessEvent(object display)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync(display);
}
Here is the code in my background worker DoWork event:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
3rdPartyControl displayControl = new 3rdPartyControl();
displayControl.ImageHost = (ImgHost)e.Argument;
Bitmap b = displayControl.GetBitmap();
var mBitmap = b.GetHbitmap();
BitmapSource bs;
try
{
bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
mBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
bs.Freeze();
}
catch (System.Exception ex) { throw ex; }
finally
{
DeleteObject(mBitmap);
}
e.Result = bs;
}
Here is the code in RunWorkerCompleted event:
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, (ThreadStart)delegate()
{
this.imgSource.Source = (BitmapSource)e.Result;
});
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, (ThreadStart)delegate()
{
this.imgSource.Source = (BitmapSource)e.Result;
});
}
System.Windows.Threading.DispatcherPriority.ApplicationIdle means Operations are processed when the application is idle.
What if the application is always busy and never idle? The requests will be queued and the app slows down.
However I haven't tested this because I don't have the source code of your app.

Resources