I want to show 4 videos at the same time in Windows Forms using Task. I have 4 video play clicks. When I click the first video play button, first video plays, when I click the second video play button, second video plays and first video continue to play at same time. But, when I click third video play button; first video stops and second video and third video plays at the same time. In the same way, when I click the fourth video play button, the second video stops, just third and fourth video plays at the same time.
My code:
private async void play1_Click(object sender, EventArgs e)
{
string inputPath = textBox1.Text;
await Task.Run(() => {
ReadFrames1(inputPath); });
}
and
public void ReadFrames1(string inputPath)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(inputPath);
for (int i = 0; i < vFReader.FrameCount; i++)
{
Bitmap videoFrame = vFReader.ReadVideoFrame();
System.Drawing.Image pic = resizeImage(new Bitmap(videoFrame), new Size(305, 267));
pictureBox1.Image = new Bitmap(pic);
}
vFReader.Dispose();
vFReader.Close();
}
}
play2_Click(), play3_Click(), play4_Click() methods are same with play1_Click(). (I mean for example play2_Click() method calls ReadFrames2() and shows on PictureBox2.) Where I am wrong?
For multithreading via WinForms use BackgroundWorker.
here is a code example which works for me. hope it will help you:
public Form1()
{
InitializeComponent();
}
private BackgroundWorker CreateBackgroundWorker()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += ReadFrames;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
return worker;
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
Button playButton = (Button) e.Result;
playButton.Enabled = true;
}
private void ReadFrames(object sender, DoWorkEventArgs e)
{
BackgroundWorker backgroundWorker = (BackgroundWorker) sender;
(string path, PictureBox pictureBox, Button playButton) arguments = ((string, PictureBox, Button)) e.Argument;
using(var vFReader = new VideoFileReader())
{
vFReader.Open(arguments.path);
for (int i = 0; i < vFReader.FrameCount; i++)
{
arguments.pictureBox.Image = new Bitmap(vFReader.ReadVideoFrame(), arguments.pictureBox.Size);
}
vFReader.Dispose();
vFReader.Close();
}
e.Result = arguments.playButton;
}
private void play1_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox1.Text, pictureBox1, play1));
play1.Enabled = false;
}
private void play2_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox2.Text, pictureBox2, play2));
play2.Enabled = false;
}
private void play3_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox3.Text, pictureBox3, play3));
play3.Enabled = false;
}
private void play4_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox4.Text, pictureBox4, play4));
play4.Enabled = false;
}
Related
I have put together a list of files that I want played from a specific directory. The videos/pictures are displayed on Windows Media Player. After the end of one video, I want the play button to be pressed to play the next video. Currently, my code is set up to have a button pressed to go to the next file in the list, as well as a play button being pressed to display the image (buttons are pressed using a timer, but this is inconvenient because some videos do not get played for the full time). Video URLS are pulled from textboxes that are filled with xml or file path information.
private void Form1_Load(object sender, EventArgs e)
{
axWindowsMediaPlayer1.stretchToFit = true;
axWindowsMediaPlayer1.uiMode = "none"; //disables the play, pause, etc. buttons at the bottom of the windows media player//
listView1.Items.Clear(); //clears listview items//
Repopulate(); //calls repopulate function//
refreshtimer.Interval = 5 * 60 * 1000;
//timer for when images need to be displayed//
Timer tmr = new Timer();
int result = int.Parse(textBox2.Text);
tmr.Interval = result * 60 * 1001;
tmr.Tick += new EventHandler(timer1_Tick);
tmr.Start();
}
private void Repopulate()
{
foreach (var d in System.IO.Directory.GetFiles(textBox3.Text))
{
var dirName = new DirectoryInfo(d).Name;
listView1.Items.Add(dirName);
}
foreach (ListViewItem item in listView1.Items)
{
item.Selected = true;
listBox1.Items.Add(item.Text);
}
}
//hidden button that acts as a "play" button, taking url from textbox 1, playing the video, and looping it until it is time for the next image//
private void button1_Click(object sender, EventArgs e)
{
// MessageBox.Show(textBox4.Text);
axWindowsMediaPlayer1.URL = textBox4.Text;
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer1.settings.setMode("loop", true);
}
// timer that clicks button one//
private void timer1_Tick(object sender, EventArgs e)
{
button1.PerformClick();
}
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
}
//when the tvdisplay is shown, start button is clicked and button 1 (play button) is clicked//
private void TVDisplay_Shown(object sender, EventArgs e)
{
startbutton.PerformClick();
button1.PerformClick();
}
//hidden behind windows media player//
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Timer tmr = new Timer();
int result = int.Parse(textBox2.Text);
tmr.Interval = result * 60 * 1000;
//int result = int.Parse(textBox3.Text);
// tmr.Interval = 1 * 60 * 1000;
//tmr.Interval = 180000;
tmr.Tick += new EventHandler(timer2_Tick);
tmr.Start();
//textBox2.Clear();
var path = textBox3.Text;
textBox4.Text = path + listBox1.SelectedItem.ToString();
}
private void refreshtimer_Tick(object sender, EventArgs e)
{
listBox1.BeginUpdate();
int x = listBox1.SelectedIndex;
listBox1.Items.Clear();
listView1.Items.Clear();
Repopulate();
//selects the first index once files are repopulated//
listBox1.SelectedIndex = x;
listBox1.EndUpdate();
}
//hidden behind windows media display//
private void startbutton_Click(object sender, EventArgs e)
{
startbutton.Enabled = false;
timer3.Interval = 10000; //time in milliseconds
timer3.Tick += timer3_Tick;
timer3.Start();
//startbutton.Enabled = false;
if(listBox1.Items != null)
{
MessageBox.Show("There is no content entered for display.", "Error");
Application.Exit();
}
else {
listBox1.SelectedIndex = (listBox1.SelectedIndex + 1) % listBox1.Items.Count;
}
}
private void timer2_Tick(object sender, EventArgs e)
{
startbutton.PerformClick();
}
private void timer3_Tick(object sender, EventArgs e)
{
startbutton.Enabled = true;
timer3.Stop();
}
}
If a timer is the most practical element to use, what would be a better way to implement it?
I want to run two media players in one form. The same video will be played on both media players and will be played at the same time. There should be no seconds difference between the two media players. When I press the "play" button, both media players should play at the same time.
When the "play" button is pressed, both media players start to play the same video. But there is a time difference of almost one second between the two videos. How can I remove this time difference? Please help.
My code ;
public Form1()
{
InitializeComponent();
}
private void LoadButton_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
axWindowsMediaPlayer1.URL = openFileDialog1.FileName;
axWindowsMediaPlayer2.URL = openFileDialog1.FileName;
}
}
private void PlayButton_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer2.Ctlcontrols.play();
}
private void Form1_Load(object sender, EventArgs e)
{
t = new Timer();
t.Interval = 100;
t.Tick += new EventHandler(t_Tick);
axWindowsMediaPlayer1.OpenStateChange += new AxWMPLib._WMPOCXEvents_OpenStateChangeEventHandler(axWindowsMediaPlayer1_OpenStateChange);
}
void t_Tick(object sender, EventArgs e)
{
trackBar1.Value = (int)this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
}
private void axWindowsMediaPlayer1_OpenStateChange(object sender, AxWMPLib._WMPOCXEvents_OpenStateChangeEvent e)
{
if (axWindowsMediaPlayer1.openState == WMPLib.WMPOpenState.wmposMediaOpen)
{
trackBar1.Value = 0;
trackBar1.Maximum = (int)axWindowsMediaPlayer1.currentMedia.duration;
t.Start();
}
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.currentPosition = trackBar1.Value;
axWindowsMediaPlayer2.Ctlcontrols.currentPosition = trackBar1.Value;
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
Going off of this... https://www.codeproject.com/Articles/841751/MultiThreading-Using-a-Background-Worker-Csharp, I'm trying to have my program do some work in the background on a separate BackGroundWorker. The operation works very well with the exception that myWorker_ProgressChanged does not update the label lbl_status_totalFilesNotCurrent.Content when called from within the myWorker_DoWork foreach loop sendingWorker.ReportProgress(cnt); Im not able to figure out why this part isn't working per the codeproject example.
follow up question... Is the background worker the preferred method for this sort of task, or should i be using tasks? https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-based-asynchronous-programming. Im starting to get the sense that background worker is deprecated.
private BackgroundWorker myWorker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
currentUser.name = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
lbl_IndProj.MouseEnter += new MouseEventHandler(changeFontColor);
lbl_IndProj.MouseLeave += new MouseEventHandler(resetFontColor);
myWorker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
myWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
myWorker.ProgressChanged += new ProgressChangedEventHandler(myWorker_ProgressChanged);
myWorker.WorkerReportsProgress = true;
myWorker.WorkerSupportsCancellation = true;
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
if (!myWorker.IsBusy)
{
myWorker.RunWorkerAsync(currentIndex);
}
}
protected void myWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker sendingWorker = (BackgroundWorker)sender;
Index ci = (Index)e.Argument;
int cnt = 0;
foreach (KeyValuePair<int, Project> project in currentIndex.projects)
{
foreach (KeyValuePair<int, IndexedDirectory> directory in project.Value.IndexedDirectories)
{
foreach (KeyValuePair<int, IndexedFile> indexedfile in directory.Value.IndexedFiles)
{
try
{
List<IndexedFile> ood = currentIndex.getOutOfDateIndexedFiles();
if (ood.Contains(indexedfile.Value))
{
cnt++;
indexedfile.Value.extractInfo();
lbl_status.Content = indexedfile.Value.LongName;
sendingWorker.ReportProgress(cnt);
}
}
catch { }
}
}
}
}
protected void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbl_status_totalFiles.Content = currentIndex.getAllIndexedFiles().Count().ToString();
lbl_status_totalFilesNotCurrent.Content = currentIndex.getOutOfDateIndexedFiles().Count().ToString();
}
protected void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int cnt = e.ProgressPercentage;
int report = currentIndex.getOutOfDateIndexedFiles().Count() - cnt;
lbl_status_totalFilesNotCurrent.Content = report.ToString();
}
I am working on a simple mediaplayer application. It works great but I want to add some extra features. I have added a trackbar control.How can i set trackbar length the same as the music's length ?
Like if the song is halfways the trackbars halfways.This is what I have so far
string[] files, indexed_files;
private void button3_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK) {
files = ofd.SafeFileNames;
indexed_files = ofd.FileNames;
for (int i = 0; i < files.Length; i++)
{
listBox1.Items.Add(files[i]);
}
}
button4.Enabled = true;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axWindowsMediaPlayer1.URL = indexed_files[listBox1.SelectedIndex];
progressBar1.Maximum =(int) axWindowsMediaPlayer1.currentMedia.duration;
axWindowsMediaPlayer1.PlayStateChange += axWindowsMediaPlayer1_PlayStateChange;
}
void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
trackBar1.Value = (int)axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
}
int index = 0;
private void button4_Click(object sender, EventArgs e)
{
if (listBox1.Items.Count != 0) {
axWindowsMediaPlayer1.URL = indexed_files[index];
trackBar1.Maximum = (int)axWindowsMediaPlayer1.currentMedia.duration;
index++;
index = (index % listBox1.Items.Count);
}
}
This will bring you the desired outcome.In my example i just placed the url in the form load for demonstration purposes.The openstatechanged event its to set the trackbar maximum since you need to wait for the player to load the file,after that the code its pretty self-explanatory:
public partial class Form1 : Form
{
Timer t;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
axWindowsMediaPlayer1.URL = "YourUrlHere";
t = new Timer();
t.Interval = 1000;
t.Tick += new EventHandler(t_Tick);
}
void t_Tick(object sender, EventArgs e)
{
trackBar1.Value = (int)this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
}
private void axWindowsMediaPlayer1_OpenStateChange(object sender, AxWMPLib._WMPOCXEvents_OpenStateChangeEvent e)
{
if (axWindowsMediaPlayer1.openState == WMPLib.WMPOpenState.wmposMediaOpen)
{
trackBar1.Maximum = (int)axWindowsMediaPlayer1.currentMedia.duration;
t.Start();
}
}
}
Yes its a timer:),and probably it is best to set it bellow 1000 for reasons of delay.
So you should now add a timer and insert the following code in timer Tick event handler:
trackbar.Value = this.axWindowsMediaPlayer1.ctlControls.CurrentPosition;
I don't have a thorough knowledge about controlling threads in c#. I want to create a progress bar while running a method.
I have two forms:
Form1 is the form which show up as you run the app. It has a button called btnScrape. When it is clicked the method should be called, the form with the progress bar should show up. Form1 should be disabled to the user until the progress bar is completed.
ProgressBarForm - this has the progress bar and a label.
The code is as follows.
//In Form1.cs I have a button.
private void btnScrape_Click(object sender, EventArgs e)
{
//gather data for folloeing parameters from the form.
Controller cntrlr = new Controller(urlFilePath, destinationPath, destinationfilename,cmbDepth.SelectedIndex);
cntrlr.Vmain(); // this is the method in controller class. while this is running i want show the progress bar.
}
// in Contrller class
class Controller{
List<string> urlList = null;
URLFileReader urlFileReader = null;
HTTPWorker httpWorker = null;
SourceReader srcreader = null;
ReportWriter reportWriter = null;
string urlFilePath, destinationPath, destinationFileName;
int depth;
public Controller(string urlFilePath,string destinationPath,string destinationFileName,int depth)
{
this.urlFilePath = urlFilePath;
this.destinationPath = destinationPath;
this.destinationFileName = destinationFileName;
this.urlList = new List<string>();
this.urlFileReader = new URLFileReader();
this.httpWorker = new HTTPWorker(this.destinationPath);
this.reportWriter = new ReportWriter(this.destinationPath,this.destinationFileName);
this.srcreader = new SourceReader(this.reportWriter);
this.depth = depth;
}
//this is the method
public void Vmain(){
this.urlFileReader.ReadURL(urlFilePath);
this.urlList = urlFileReader.geturlList();
string pageSrc;
foreach (string requestUrl in urlList)
{
//do sruff for requestUrl
//the progressbar should move as the urlList iterate.
//additionally i want the label on the top of progress bar to display the current "requestUrl"
//as the urlList is over i want quit from the progressbar window and come back to Form1. Till the progrss bar is completed Form1 should be disabled for the user.
}
}
}
Please explain what is happening there and give a working code if you can. Thank you in advance. There were not any perfect answer that worked for me, even though I spent two days for this. I tried with BackgroundWorkerand threads. But no solution found. :(
In the main form you could use this code:
private Progressfrm _loadForm;
private void ShowProgress()
{
ToggleForm();
_loadForm = new Progressfrm();
_loadForm.ShowDialog();
var tcheck = new Thread(CheckLoadedProgress);
tcheck.Start();
//do stuff here
}
private void CheckLoadedProgress()
{
while (_loadForm.IsAccessible) { }
ToggleForm();
}
private void ToggleForm()
{
Invoke(new Action(() => Enabled = !Enabled));
}
private void btnScrape_Click(object sender, EventArgs e)
{
var tform = new Thread(ShowProgress);
tform.Start();
}
Then the Progress-Form will appear until it is filled:
private ProgressBar _progressBar;
private void Progressfrm_Shown(object sender, EventArgs e)
{
_progressBar = new ProgressBar { Size = new Size(100, 20), Location = new Point(10, 10) };
Controls.Add(_progressBar);
_progressBar.Show();
Refresh();
LoadProgress();
}
private void LoadProgress()
{
while (_progressBar.Value < 100)
{
_progressBar.Value++;
Thread.Sleep(100);
}
Close();
}
On this Form you have to add the Event Shown and add the code like in my example. Hope this helps.
Use BackgroundWorker class to output progressBar and statusLabel changes:
BackgroundWorker bgw;
private void btnScrape_Click(object sender, EventArgs e)
{
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
bgw.RunWorkerAsync();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
bgw.ReportProgress(i);
}
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
This is only an example how to update controls in an asynchron way.