I have a video file playing in a media element. I need to keep it playing, thus I tried:
me.play();
me.MediaEnded += new RoutedEventHandler(me_MediaEnded);
With this event method:
//loop to keep video playing continuously
void me_MediaEnded(object sender, EventArgs e)
{
//play video again
me.Play();
}
However the above does not replay the video file. Why? What did I do wrong?
According to a post on MSDN:
Play() starts from the current position therefore you have to first go to the starting place and then play it again.
So you have to reset the position before replaying:
me.Position = TimeSpan.FromSeconds(0);
me.Play();
You could also use a Storyboard to control and loop the video without needing to hook events or do any code-behind work. This is the recommended solution on MSDN and is a more elegant and proper solution for MVVM design.
Read more on MSDN here, includes examples:
http://msdn.microsoft.com/en-us/library/ms741866%28v=vs.100%29.aspx
I got it to work with this:
class MyMediaPlayer : MediaPlayer
{
private bool looping;
public MyMediaPlayer() : base()
{
looping = false;
base.MediaEnded += new EventHandler(mediaEnded);
}
public MyMediaPlayer(string _file) : base()
{
looping = false;
base.Open(new Uri(_file, UriKind.Relative));
base.MediaEnded += new EventHandler(mediaEnded);
}
public bool Looping
{
get { return looping;}
set { looping = value; }
}
public void playLooping()
{
looping = true;
base.Play();
}
public void playLooping(string _file)
{
looping = true;
base.Open(new Uri(_file, UriKind.Relative));
base.Play();
}
public void play()
{
looping = false;
base.Play();
}
public void play(string _file)
{
looping = false;
base.Open(new Uri(_file, UriKind.Relative));
base.Play();
}
public void stop()
{
looping = false;
base.Stop();
}
private void mediaEnded(object sender, EventArgs e)
{
if(looping)
{
base.Position = new TimeSpan(0, 0, 0);
base.Play();
}
}
}
Hope this answers your question.
I don't know the reason but this never worked for me with a GIF:
me.Position = TimeSpan.FromSeconds(0);
me.Play();
My GIF stops playing after the first iteration.
The solution is:
<MediaElement x:Name="me"
MediaEnded="MediaElement_MediaEnded"
LoadedBehavior="Play" />
Code:
private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
me.Position = TimeSpan.FromMilliseconds(1);
}
1 ms is used while 0ms might stop the playback you cannot run it again with a 'Play' method.
Related
I need to save an image to disk that came from a web-cam between 5 and 10 seconds ago from when the "save" command comes in via serial port.
To get there, I have the webcam going into a pictureBox.Image (using opencv4), and then 2 Bitmap variables. Every 5 seconds a timer ticks, and Stored_bitmap_2 = Stored_bitmap_1, then Stored_bitmap_1 = (bitmap) pictureBox.Image.
When the right serial command comes in, I try to
Stored_image_2.Save("C:\Users\GreenWorld\Desktop\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
and I get a run-time error of invalid parameter.
When I do the same thing in a stand-alone project with some buttons (inside the button-click event handler), it works every time.
When I do this inside the serialPort_DataReceived handler, I get all kinds of cross-thread errors. So, I moved the save attempt to its own subroutine, and that fixed that but now this.
I am by no means a professional programmer, I'm an engineer with a simple problem and I can usually write a little simplistic code to fix my immediate issue. Please go easy on me in the explanation :-)
Sample code:
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Weld_picture
{
public partial class Form1 : Form
{
// Create class-level accessible variables
int Welding_camera_ID = 1;
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
string Serial_command = "";
Bitmap Stored_image_1;
Bitmap Stored_image_2;
bool Image_saved = false;
string Station_ID = "GWM-PWS-01";
string File_name = "";
private void CaptureCamera() // from someone else's sample code
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback() // from someone else's sample code
{
frame = new Mat();
capture = new VideoCapture(Welding_camera_ID);
capture.Open(Welding_camera_ID);
if (capture.IsOpened())
{
while (isCameraRunning)
{
capture.Read(frame);
image = BitmapConverter.ToBitmap(frame);
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = image;
}
}
}
public Form1()
{
InitializeComponent();
SerialPort1.Open();
}
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string dummy;
char CR = (char)0x0D;
while (SerialPort1.BytesToRead > 0)
{
Serial_command += (char)SerialPort1.ReadByte();
}
while (Serial_command.IndexOf(CR) > 0)
{
dummy = Serial_command.Substring(0, Serial_command.IndexOf(CR));
Serial_command = Serial_command.Substring(Serial_command.IndexOf(CR) + 1, (Serial_command.Length - (Serial_command.IndexOf(CR) + 1)));
Serial_command.Trim();
dummy.Trim();
proc_Process_serial_data(dummy);
}
}
//*************************************************************************************************************************************
/* the first timer is a 5-second interval. It's the "memory" function so that if/when the save-to-disk is triggered I can store the last-time-shutter-open image */
//*************************************************************************************************************************************
private void Timer_picture_interval_Tick(object sender, EventArgs e)
{
checkBox1.Checked = !checkBox1.Checked;
Timer_picture_interval.Stop();
Stored_image_2 = Stored_image_1;
Stored_image_1 = (Bitmap) pictureBox1.Image;
Timer_picture_interval.Start();
}
//*************************************************************************************************************************************
// the second timer is a 30-second interval. It's the way to turn capture off if the PLC/camera box somehow goes off-line
//*************************************************************************************************************************************
private void Timer_camera_powerdown_Tick(object sender, EventArgs e)
{
if (isCameraRunning)
capture.Release();
isCameraRunning = false;
Timer_picture_interval.Stop();
}
//*************************************************************************************************************************************
private void proc_Process_serial_data(string Serial_string)
{
if (Serial_string.IndexOf("Still here") > 0)
{
if (!isCameraRunning)
CaptureCamera();
isCameraRunning = true;
}
if (Serial_string.IndexOf("Sun's up") > 0)
{
Timer_picture_interval.Start();
Timer_camera_powerdown.Start();
}
if (Serial_string.IndexOf("It's dark") > 0)
{
if ((Stored_image_2 != null) && (!Image_saved)) // in case there's 2 subsequent requests to save the same thing (weld stutter)
{
File_name = "C:\\Users\\GreenWorld\\Desktop\\" + Station_ID + " D" + DateTime.Now.ToString("yyyy_MM_dd THH_mm_ss") + ".jpg";
Stored_image_2.Image.Save("C:\\Users\\GreenWorld\\Desktop\\test.bmp" , System.Drawing.Imaging.ImageFormat.Bmp );
Image_saved = true;
Timer_picture_interval.Stop();
}
Timer_camera_powerdown.Start();
}
}
}
}
You likely be able to fix the cros-threading error by simply calling your proc_Process_serial_data() method within an Invoke() call.
Change:
proc_Process_serial_data(dummy);
To:
this.Invoke((MethodInvoker)delegate ()
{
proc_Process_serial_data(dummy);
});
Also, these two lines aren't actually doing anything:
Serial_command.Trim();
dummy.Trim();
To Trim() the strings, you have capture the returned strings and re-assign them to the original variables:
Serial_command = Serial_command.Trim();
dummy = dummy.Trim();
I'm currently writing an app in c#, where this app will play background music once it started. And the button clicking sound and music shall stop when I press the mute button, or play again when unmuted.
namespace WindowsFormsApp1
{
public partial class mainMenu : Form
{
public bool sound = true; //variable of whether the sound is on or not
System.Media.SoundPlayer bgm = new System.Media.SoundPlayer(#"C:\Users\User\Desktop\HCI\New folder\bgm.wav");
public bool soundval //for other form to access sound variable value
{
get
{
return sound;
}
set
{
sound = value;
}
}
public mainMenu()
{
InitializeComponent();
play();
}
public void play() //function to play music
{
bgm.PlayLooping();
}
public void stop//function to stop music
{
bgm.Stop();
}
private void soundButton_Click(object sender, EventArgs e) //button that mute or unmute the sound (by changing sound value)
{
if (sound)
{
bgm.Stop();
sound = false;
}
else
{
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"C:\Users\User\Desktop\HCI\New folder\button.wav"));
p2.Play();
play();
sound = true;
}
}
private void easy_Click(object sender, EventArgs e) //proceed to other form
{
if (sound)
{
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"C:\Users\User\Desktop\HCI\New folder\button.wav"));
p2.Play();
}
Easy game2 = new Easy();
game2.Tag = this;
game2.Show(this);
Hide();
}
}
}
Until here, the app works fine. But then if I muted the sound and proceed to other form, the music will play again, the button sound will also play if I press anything on any button on that particular form.
Partial code of my other form(easy_Click):
mainMenu mmenu = new mainMenu();
private void thirdchoice_Click(object sender, EventArgs e)
{
if (mmenu.soundval) //to get the value from first form, button sound should play only when value is true
{
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"C:\Users\User\Desktop\HCI\New folder\button.wav"));
p2.Play();
}
if (ansNum == choice3num) goodnews();
else badnews();
}
Not only music, but the button clicking sound is playing as well. It looks like the sound value set to true when proceed to second form, even though it was false in first form.
I been stuck on this issue for a long time, changing here and there, but nothing work.
Really appreciate if someone could help on this. Thanks!
I have a bit strange problem, which I find hard to debug
Sometimes I can't close my program and it freezes when I try to close it.
I made a large program for video image recognition.
I made a special button to close the camera. This button works with this by calling a function below, and it indeed, it does work.
private void exitcamera()
{
FinalVideo.SignalToStop();
FinalVideo.WaitForStop();
FinalVideo = null;
}
Notice that the original video was started like this
private void buttonStartCamera_Click(object sender, EventArgs e)
{
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
Now my problem seems (and this is a guess because I can't debug this moment)
That some thread is still active wanting to update the main form with data.
However it might not be able to do so since that one is closing.
I think something like that is going on so I wrote on the main application form
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// Thread.Sleep(1000); // not sure about these delays might help syncing threads
ExitCamera();
Thread.Sleep(1000);
}
However with that last code in place the program has even more trouble to exit.
I would like to send the subthreads an exit, but I dont know their names (if they have a name), I dont know how to list them or to instruct them to stop they are in another dll not my part of the code. From some dll's I dont have the code.
So are there ways of listing sub threads and then close them one by one, if one presses the uppercorner right cross to exit the application?
Well I managed to debug the program, and finally found what caused the problem.
It is a little bit strange since as a button I could stop the camera using the exitcamera function.
However, inside a _formclosing event the same routine didn't work although it worked after I had marked out the waitforstop function.
private void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
I am still a bit confused about it, why this wont work in case a closing event. But it seems to be solved by this.
Maybe you have memory leaks problems caused by the event. You could try to unhook the event while exiting the programm :
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
Maybe this will help.
This helped with another problem when I wanted to show a preview, click a "grab" button, change the resolution of the camera from low res to high res, grab an image, and then change back to low res for the preview. Here is what worked, even though I had to abandon it because stopping and starting the camera reset the auto exposure so the picture was awful on the grabbed image:
using AForge.Video;
using AForge.Video.DirectShow;
public partial class Form1 : Form
{
private int PreviewRefreshDelayMS = 40;
private FilterInfoCollection VideoCaptureDevices;
private VideoCaptureDevice CustomerWebcam;
private int CustomerWebcam_CapabilitiesIndexMin;
private int CustomerWebcam_CapabilitiesIndexMax;
private bool bCustomerWebcam_capture;
private Bitmap CustomerWebcam_bitmap;
private System.DateTime CustomerWebcam_nextframetime = DateTime.Now;
public Form1()
{
InitializeComponent();
}
// Some good info to make this more robust
// http://haryoktav.wordpress.com/2009/03/21/webcam-in-c-aforgenet/
//
private void button1_Click(object sender, EventArgs e)
{
CustomerWebcam = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
CustomerWebcam.NewFrame += new NewFrameEventHandler(CustomerWebcam_NewFrame);
int indexMin = -1;
int MinPixels = 0;
int indexMax = -1;
int MaxPixels = 0;
for (int i = 0; i < CustomerWebcam.VideoCapabilities.Length; i++)
{
int pixels = CustomerWebcam.VideoCapabilities[i].FrameSize.Height * CustomerWebcam.VideoCapabilities[i].FrameSize.Width;
if (indexMin == -1) { indexMin = i; MinPixels = pixels; }
if (indexMax == -1) { indexMax = i; MaxPixels = pixels; }
if (pixels < MinPixels) { indexMin = i; MinPixels = pixels; }
if (pixels > MaxPixels) { indexMax = i; MaxPixels = pixels; }
}
CustomerWebcam_CapabilitiesIndexMin = indexMin;
CustomerWebcam_CapabilitiesIndexMax = indexMax;
CustomerWebcam.VideoResolution = CustomerWebcam.VideoCapabilities[indexMin];
CustomerWebcam.DisplayPropertyPage(IntPtr.Zero);
CustomerWebcam.Start();
}
void CustomerWebcam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (CustomerWebcam_bitmap != null)
{
CustomerWebcam_bitmap.Dispose();
CustomerWebcam_bitmap = null;
}
if (bCustomerWebcam_capture)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
System.Random rnd = new Random();
CustomerWebcam_bitmap.Save("img" + Convert.ToString((int)(rnd.NextDouble() * 10000000)) + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
bCustomerWebcam_capture = false;
((Bitmap)eventArgs.Frame).Dispose();
}
else
if (DateTime.Now > CustomerWebcam_nextframetime)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = CustomerWebcam_bitmap;
CustomerWebcam_nextframetime = DateTime.Now.AddMilliseconds(PreviewRefreshDelayMS);
((Bitmap)eventArgs.Frame).Dispose();
}
}
private void Form1_Load(object sender, EventArgs e)
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
comboBox1.Items.Add(VideoCaptureDevice.Name);
}
comboBox1.SelectedIndex = 0;
}
private void button2_Click(object sender, EventArgs e)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!(CustomerWebcam == null))
if (CustomerWebcam.IsRunning)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
}
private void button4_Click(object sender, EventArgs e)
{
bCustomerWebcam_capture = true;
}
}
One other thing to mention ... the AForge library was the most consistent way I was able to find for using a webcam to grab a still image and save as a JPEG without delving into the world of Windows 8 metro apps. I was hoping to use OpenCV.NET, or just the regular .NET API with DirectShow or WIA, but this was the most simple and it worked for me.
And here are some good samples that were hard to find but very useful: https://github.com/mdavid/aforge.net
I was dealing with this problem. Here is a simple way to stop the camera and close Win Form.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
FinalVideo = null;
}
}
}
In my situation WaitForStop() was needed, but the code execution was deading inside the method.
I've replaced it right after the call to SignalToStop(), with:
while (m_Device.IsRunning) { }
This is the code involved on the AForge library:
public bool IsRunning
{
get
{
if (this.thread != null)
{
if (!this.thread.Join(0))
{
return true;
}
this.Free();
}
return false;
}
}
public void WaitForStop()
{
if (this.thread != null)
{
this.thread.Join();
this.Free();
}
}
Edit: this didn't fix the hang the 100% of times. Sometimes a call to a com object (mediaControl.Stop();) on the WorkerThread() method just took forever.
Avoid direct interaction with the form - hope to have a better solution than timer but solves problem. I
Static helper class
public static Bitmap StaticBitmap = new Bitmap(100,100);
Form
public void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
lock (StaticHelper.StaticBitmap)
{
using (Bitmap b = (Bitmap)eventArgs.Frame)
{
StaticHelper.StaticBitmap = (Bitmap)b.Clone();
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (StaticHelper.StaticBitmap)
{
pictureBox1.Image = (Bitmap)StaticHelper.StaticBitmap.Clone();
}
}
This will destroy your problem ( I have had this problem, i tried)
using System.Threading;
bool photo_was_taken = false;
private void buttonStartCamera_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(exitcamera));
thread.Start();
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
private void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
// what you want to do ( your code is here )
photo_was_taken = true;
}
private void exitcamera()
{
while (!photo_was_taken)
{
Thread.Sleep(5); // you can change wait milliseconds
}
FinalVideo.SignalToStop();
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
//FinalVideo.WaitForStop();
while (FinalVideo.IsRunning)
{
FinalVideo.Stop();
// FinalVideo = null; >> // that is not condition
}
}
This is what you need, 100% working solutions:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
Invoke((MethodInvoker) delegate
{
_videoSource.SignalToStop();
_videoSource.WaitForStop();
});
}
Please, let me add my working solution on closing a webcam with the wonderful library AForge.NET. It´s a pitty it development has been abandoned.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (videoCaptureSource != null)
{
while (videoCaptureSource.IsRunning) // Perhaps you need to limit the number of iterations
{
videoCaptureSource.SignalToStop();
videoCaptureSource.WaitForStop();
if (videoSourcePlayer != null)
{
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
//videoSourcePlayer.NewFrame -= new NewFrameEventHandler(videoSourcePlayer_NewFrame); // Uncomment this line if you have added an event handler
}
Thread.Sleep(3000);
}
videoCaptureSource = null;
videoDevices = null;
videoSourcePlayer = null;
}
}
When I only needed the frame attaching an event handler to the VideoCaptureDevice (not the VideoSourcePlayer) I couldn´t stop the video from the VideoCaptureDevice, instead I used an invisible VideoSourcePlayer and stopped it from there.
i tried some solution, but nothing work.
i partial solved adding a thread sleep after WaitForStop
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
Thread.Sleep(1000);
}
}
if i try to call Stop application will be freeze
Currently I am doing this in my code,
playbackElement1.AutoPlay = true;
playbackElement1.SetSource(stream, this.m_recordStorageFile.FileType);
playbackElement1.Position = new TimeSpan(0, 0, 0, 0, 5000);
playbackElement1.Play();
It doesn't work, checking for a video longer than 5 secs.
There are two problems. First, MediaElement can only set the position once the media is loaded, determined by handling the MediaOpened event. Secondly, not all media is seekable. Check by calling CanSeek. Use something like:
playbackElement1.AutoPlay = true;
// Will fire after the media has loaded
playbackElement1.MediaOpened += (source, args) =>
{
MediaElement player = (MediaElement) source;
if (player.CanSeek)
{
player.Position = new TimeSpan(0, 0, 0, 0, 5000);
}
}
playbackElement1.SetSource(stream, this.m_recordStorageFile.FileType);
Once loaded, use the NaturalDuration property to see the length of the media, converting it to a TimeSpan using HasTimeSpan and TimeSpan properties if needed.
In a nutshell, you will need to add a Slider underneath the MediaElement just like in any video player...
- the Slider will update the player current position
- the Timer will update the slider every 300 millisecond with the current player position
Code:
<Slider x:Name="videoSlider" Thumb.DragStarted="videoSlider_DragStarted" Thumb.DragCompleted="videoSlider_DragCompleted" Margin="10,0,10,30" Height="18" VerticalAlignment="Bottom"/>
<MediaElement x:Name="videoPlayer" Margin="4,59,152,53" Volume=".5" MediaOpened="videoPlayer_MediaOpened">
[This is picture for the Media-Element with the Slider][1]
Now we have a media element and a slider... Next: C# Code :)
public partial class MainWindow : Window
{
bool isSeekingMedia = false;
DispatcherTimer seeker; // the timer to update the Slider
public MainWindow()
{
InitializeComponent();
player = new MediaPLayer();
IsPlaying(false);
seeker = new DispatcherTimer();
seeker.Interval = TimeSpan.FromMilliseconds(200);
seeker.Tick += Seeker_Tick;
}
///Seeker_Tick will update the Slider position while the video is playing
private void Seeker_Tick(object sender, EventArgs e)
{
try
{
MediatimeCounter.Content = String.Format("{0:hh}:{0:mm}:{0:ss}/{1:hh}:{1:mm}:{1:ss}", videoPlayer.Position, videoPlayer.NaturalDuration.TimeSpan);
if (!isSeekingMedia)
{
videoSlider.Value = videoPlayer.Position.TotalSeconds;
}
}
catch (Exception ex) { }
}
//This code is going to set Seeking to true to avoid playing the video if the user is changing the slider position... it kinda causes a performance issue.. so it's better to update the video position once the slider dragging event is completed.
private void videoSlider_DragStarted(object sender, RoutedEventArgs e)
{
isSeekingMedia = true;
}
//and this code is to update the video position based on the slider value.
private void videoSlider_DragCompleted(object sender, RoutedEventArgs e)
{
if (videoPlayer.Source != null)
{
isSeekingMedia = false;
this.videoPlayer = player.SeekVideo(videoPlayer, videoSlider.Value);
}
}
I have a Winforms app in C# that calls calls a method asynchronously and uses a callback.
I would like to display an animated gif to let the end user know that work is being done.
I would like to have the animated gif hover over the center of the form.
How can I do this?
Update:
Thanks. I guess the step I was missing was to use a Picture Box to hold the gif.
The following seems to be doing the trick of showing the gif and like jmatthews3865 said below I can just set the visible property of the PictureBox to false to hide it.
private ShowAnimatedGif()
{
PictureBox pb = new PictureBox();
this.Controls.Add(pb);
pb.Left = (this.Width / 2) - (pb.Width / 2);
pb.Top = (this.Height / 2) - (pb.Height / 2);
pb.Image = Resources.AnimatedGifHere;
pb.Visible = true;
}
in your form, simply include the image with it's visible property set to false.
from the event which calls the long running async process (button1_click etc.), set the images visibility property to true. event fires, image appears, async process runs and your ui thread should still be responsive.
in your callback event set the images visible property to false to indicate that the process is complete.
Need some code to give an exact answer, but this is fairly trivial, insert the gif before you make the asynchronous call, then remove it in the callback.
This is the answer. I'm using LoadingCircle which is an animated gif component.
public partial class Form1 : Form
{
public delegate void ProcessAnimation(bool show);
ProcessAnimation pa;
public Form1()
{
InitializeComponent();
pa = this.ShowAnimation;
}
private void button2_Click(object sender, EventArgs e)
{
Thread tr = new Thread(FlushToServer);
tr.Start();
}
private void ShowAnimation(bool show)
{
if (show)
{
loadingCircle1.Visible = true;
loadingCircle2.Active = true;
}
else
{
loadingCircle1.Visible = false;
loadingCircle1.Active = false;
}
}
private void FlushToServer()
{
this.Invoke(this.pa,true);
//your long running process
System.Threading.Thread.Sleep(5000);
this.Invoke(this.pa,false);
}
}
i modify the above code a bit and it will not throw error "c# invoke or begininvoke cannot be called on a control until the window handle has been created."
namespace AnimateUI
{
public partial class Form1 : Form
{
public delegate void ProcessAnimation(bool show);
ProcessAnimation pa;
public Form1()
{
InitializeComponent();
pa = this.ShowAnimation;
pictureBox1.Visible = false;
}
private void ShowAnimation(bool show)
{
if (show)
{
pictureBox1.Visible = true;
}
else
{
pictureBox1.Visible = false;
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread tr = new Thread(StartTask);
tr.Start();
}
private void StartTask()
{
if (!this.IsHandleCreated)
this.CreateControl();
this.Invoke(this.pa, true);
System.Threading.Thread.Sleep(15000);
this.Invoke(this.pa, false);
}
}
}