I have code which loads a playlist and plays videos one after another, triggered by the PlayStateChange event of AxWindowsMediaPlayer. After reading several examples, I implemented BeginInvoke in order to delay the code while the videos play. It seems as if I need to implement EndInvoke because I am having functionality issues with my code continuing after the videos are played. How should I go about this? I could not figure it out from the posted examples and MSDN guides. Here is my code:
public void playItem(Item it)
{
player.CreateControl();
player.Enabled = true;
player.enableContextMenu = false;
player.uiMode = "none";
player.Name = "player";
player.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
WMPLib.IWMPMedia media;
WMPLib.IWMPPlaylist playlist = player.playlistCollection.newPlaylist("myplaylist");
for (int x = 0; x < _presented.count; x++)
{
media = player.newMedia(_presented.getItem(x).video);
playlist.appendItem(media);
}
player.currentPlaylist = playlist;
player.PlayStateChange += player_PlayStateChange;
}
private void player_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8)
{
this.player.BeginInvoke(new Action(() =>
{
if (p_onset)
{
player.Ctlcontrols.play();
}
}));
//Maybe Implement EndInvoke here? Unsure of the proper syntax for this scenario
}
}
Related
Im a beginner with C# I'm doing some School project using a Windows Form App, It's a simple game but I ran into some issues, I want to give a picture box control a bullet-like trajectory when the [Space] key is pressed but haven't been able to do it yet. I was instructed to do this only using Threads and NO timers.
Also I want this picture box to 'spawn' and start moving from another picture box named 'SpaceShip' but i don't know how i could do that
Of course, advice and suggestions are very welcome even if it means changing entire parts of my awful code
I tried using picturebox.Left = picturebox.Left +5; but I guess i'm doing something wrong
if (e.KeyCode == Keys.Space)
{
if(pbEnergy.Value <= 0)
{
pbEnergy.Value = 0;
System.Media.SoundPlayer SFX = new System.Media.SoundPlayer(#"C:\SFX\nolaser.wav");
SFX.Play();
}
else
{
System.Media.SoundPlayer SFX = new System.Media.SoundPlayer(#"C:\SFX\laser.wav");
SFX.Play();
pbEnergy.Value -= 10;
ThreadStart Delegate = new ThreadStart(phys);
Thread MovTh = new Thread(Delegate);
MovTh.Start();
}
}
public void phys()
{
for (int i = 0; i <= 60; i++)
{
Thread.Sleep(10);
Progress(i);
if (i == 60) //stop when value is reached
{
Thread.CurrentThread.Suspend();
}
}
}
delegate void Delegate(int n);
private void Progress(int num)
{
if (this.InvokeRequired)
{
Delegate d = new Delegate(Progress);
object[] Parameters = new object[] { num };
this.Invoke(d, Parameters);
}
else
{
picprj.Visible = true;
picprj.Left = picprj.Left + 5;
}
I expected the picture box to travel and then disappear but it finishes its trajectory and stays visible, I would appreciate some advice on this or even a better way to do it.
I have a video player which loads videos (.wav) to a playlist and scrolls through the playlist using a play queue manipulated by the playstatechange events. It works fine except for a black flicker (usually just one) that happens on the last frame of a random video (never the same spot in the play list or the same video). This also occurs on multiple computers so I am pretty sure it is not any video card settings, unless an obscure codec issue. This is for a research experiment and cannot have the flicker, it must be completely seamless. I have searched through every question and the only similar one did not involve a playlist of multiple videos, his flicker was when looping the same video, thus a totally different solution. Here is my video player creation and implementation:
public void MultipleVideos()
{
player.CreateControl();
player.Enabled = true;
player.enableContextMenu = false;
player.uiMode = "none";
player.Name = "player";
player.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
WMPLib.IWMPMedia media;
WMPLib.IWMPPlaylist playlist = player.playlistCollection.newPlaylist("myplaylist");
for (int x = 0; x < _presented.count; x++)
{
media = player.newMedia(_presented.getItem(x).video);
playlist.appendItem(media);
}
player.currentPlaylist = playlist;
}
private void player_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (!currSess.playOne)
{
if (e.newState == 8 | e.newState == 9)
{
if (e.newState == 8)
{
currSess.playQueue++;
}
}
if (currSess.playQueue+1 > player.currentPlaylist.count -1)
{
if (e.newState == 10)
{
player.uiMode = "invisible";
player.Visible = false;
displayImgs();
currSess._timer.start();
AllowControls(true);
allowItems();
player.PlayStateChange -= foo;
currSess.playQueue = 0;
}
}
}
}
I've a game with 90 grey numbers and, periodically, some of them become blue.(Simplified!)
Now i use:
Game-->Timer-->Thread-->coloring numbers
because i want use my game also when the numbers in coloration.
the code:
some variables..
public FormHome()
{
InitializeComponent();
TEstrazione = new System.Timers.Timer(10000);
TEstrazione.AutoReset = false;
TEstrazione.Elapsed += timerEstrazioneElapsed;
TEstrazione.Start();
}
private void timerEstrazioneElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
ThreadEstrazione = new Thread(cThread);
ThreadEstrazione.IsBackground = true;
ThreadEstrazione.Start();
}
private void cThread()
{
//other methods that change others controls..
coloring();
TEstrazione.Start();
}
void coloring()
{
for (int i = 0; i < 20; i++)//20 numbers to make colored
{
int num = *get random number*;
Label lbl;
lbl = (Label)panelNumembers.Controls["n" + num.ToString()];
if (lbl.InvokeRequired)
{
lbl.Invoke(new Action(coloring), new object[] { });
return;
}
lbl.BackColor = Color.DodgerBlue;
lbl.ForeColor = Color.Navy;
lbl.Refresh();
Thread.Sleep(800);
}
}
excuse me if some names are in italian but i think they aren't important.
The problem is that when the thread is coloring the label, the program locks: i can't push buttons and even close it! I think is a thread-safe problem but i don't know other ways.
As i've written, there are other methods inside a cThread, all change the controls. One of theese is:
void refreshLabel()
{
//here I always used one of the controls for the InvokeRequired
because in some cases I have so many and if I do the InvokeRequired
for each control becomes too long the code
if (label1.InvokeRequired)
{
ne.Invoke(new Action(refreshLabel), new object[] { });
return;
}
label1.Text = "xxxxx";
label1.Refresh();
label2.Text = "xxxxxxxxxxxxxxxx";
label2.Refresh();
}
In conclusion I have a lot of methods started by cThread that change a lot of controls, there is a way to make it thread safe without stretching too much code?
I apologize for the English but I'm Italian and is not easy explain the problems in an another language.
I'm using my girlfriend laptop so I'll edit my answer and give you a much better answer ASAP. the problem occurred because most of the execution is in the UI thread. you should execute most of your execution in background. when you want to update the UI you need to change context to the UI thread(only updates!).
Change coloring to:
void coloring()
{
for (int i = 0; i < 20; i++)//20 numbers to make colored
{
int num = *get random number*;
Label lbl;
lbl = (Label)panelNumembers.Controls["n" + num.ToString()];
var updateUI = new Action(() => {
lbl.BackColor = Color.DodgerBlue;
lbl.ForeColor = Color.Navy;
lbl.Refresh();
});
if (lbl.InvokeRequired)
{
Invoke(updateUI);
}
else
{
updateUI();
}
Thread.Sleep(800);
}
if there is no other blocking operations inside your code then this might work
i'm using Gmap.NET with C# WPF, and i'd like to add a large amount of markers (~6k) on the map.
But i still can't make add them asynchronously, Map is always freezing and not responding at all, until all markers will not be added...
Here is my code sample:
private void MainMap_Loaded(object sender, RoutedEventArgs e)
{
MainMap.Zoom = 12;
LoadMarkers();
}
private async void LoadMarkers()
{
await Task.Run(new Action(() =>
{
for (int i = 0; i <= 6000; i++)
{
Dispatcher.InvokeAsync(
new Action(
delegate()
{
PointLatLng point = new PointLatLng(GetRandomNumber(55.0000, 55.7510),
GetRandomNumber(36.0000, 38.9999));
var currentMarker = new GMap.NET.WindowsPresentation.GMapMarker(point);
{
currentMarker.Shape = new MarkerTemplate(this, currentMarker,
string.Empty);
currentMarker.Offset = new Point(-16, -32);
currentMarker.ZIndex = int.MaxValue;
MainMap.Markers.Add(currentMarker);
}
}
));
}
}));
}
You probably need to design a cluster marker solution for GMap. Use the Map_OnMapZoomChanged event to hide/show markers accordingly.
With a bit of a work, you might be able to achieve a cluster like the Google Maps one:
Good luck! Don't forget to open-source it when you're done :)
Newbie in programming here so please give answers with clear elaboration. Thank you.
When i do this loop for a slideshow with given number of loops, the pictures do not show in the picturebox while the loop is running.
And, i have a selectedindexchanged event somewhere so only when the loop ends, that event fires and only the last picture is shown on the picturebox.
CODE:
if (mtxtloop.Text != "")
{
int intNumberOfLoops = Convert.ToInt16(mtxtloop.Text);
for (int intAlbum = 0; intAlbum < intNumberOfLoops; intAlbum++)
{
for (int intPictures = 0; intPictures < listBoxPicturesInAlbum.Items.Count; intPictures++)
{
//Just to check position.
listboxPicturesInAlbum.SelectedIndex = intPictures;
Thread.Sleep(2000);
//Insert selecteditem into picture
//ERROR HERE: PictureBox doesn't show selecteditem
pBoxOfSelectedPicture.Image = Image.FromFile(listBoxPicturesInAlbum.SelectedItem.ToString());
}
}
}
In your original code you are simply missing a PBox_loop.Refresh();. But you are also tying up the UI thread by sending it to sleep for seconds. Never a good idea.. (Thread.Sleep() can sometimes help resolve race conditions but not here and never for more than 10-100ms)
Here is the way I would do it: Use a Timer and three variables at e.g. class level to keep track of the progress..
int intNumberOfLoops = 1;
int intLoopCounter = 0;
int pictureIndex = 0;
private void startButton_Click(object sender, EventArgs e)
{
pictureIndex = 0;
intLoopCounter = 0;
// insert error checking here!
intNumberOfLoops = Convert.ToInt16(mtxtloop.Text);
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
// final image:
if (intLoopCounter >= intNumberOfLoops)
{ // this assumes there is a selected item!
PBox_loop.ImageLocation = listBoxPicturesInAlbum.SelectedItem.ToString();
timer1.Stop();
return;
}
// the regular loop:
PBox_loop.ImageLocation = listBoxPicturesInAlbum.Items[pictureIndex];
pictureIndex++;
if (pictureIndex >= listBoxPicturesInAlbum.Items.Count)
{
pictureIndex = 0;
intLoopCounter++;
}
}
Using a Timer prevent the UI thread of being blocked without the hassle of starting a Thread of your own..