So I'm trying to use a soundplayer to load a wav file, and then fire an event after it's done loading it. Reason being is that I don't want my program to continue on until the WAV is fully loaded and ready to go (if there's another way to do this, let me know).
But unfortunately the LoadCompleted event is never firing!
Here's the last of what I tried. What am I doing wrong?
this.audio = new SoundPlayer();
audio.SoundLocation = "songs\\" + songname + ".wav";
audio.LoadAsync();
that belongs to the songdata object. Then I have this is the main class main method:
this.songdata.audio.LoadCompleted += new AsyncCompletedEventHandler(audio_LoadCompleted);
this.songdata.audio.Play();
lastly inside the main class:
void audio_LoadCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("aaa");
}
The file starts playing, but the message box never appears. BTW I'm using Visual Studio 2010 and .NET 4.0.
I got the following code to send me a LoadCompleted event, I had, however, the "event callback function" in the same class as the SoundPlayer object.
class MediaPlayer{
System.Media.SoundPlayer soundPlayer;
public MediaPlayer(MemoryStream stream){
soundPlayer = new System.Media.SoundPlayer(stream);
soundPlayer.LoadCompleted += new AsyncCompletedEventHandler(player_LoadCompleted);
soundPlayer.Load();
}
public void Play(){
soundPlayer.Play();
}
// Handler for the LoadCompleted event.
private void player_LoadCompleted(object sender, AsyncCompletedEventArgs e){
Console.WriteLine("LoadCompleted");
}
}
Related
In the documentation of the Siemens TIA-Portal Openness API you can read the following:
There is an event, when a confirmation box opens, and an event when the confirmation is given by the user.
//Register event handler for Notification-Event
....
tiaPortal.Notification += TiaPortal_Notification;
....
private static void TiaPortal_Notification(object sender, NotificationEventArgs e)
{
....
}
//Register event handler for Confirmation-Event
....
tiaPortal.Confirmation += TiaPortal_Confirmation;
....
private static void TiaPortal_Confirmation(object sender, ConfirmationEventArgs e)
{
....
}
The documentation gives this much information on reacting to the events
I want to react on the notification event. But the NotificationEventArgs Class does not contain an result attribute which i can write on, and does not contain any method of some kind to send a confirmation. There is only one writeable attribute, called IsHandled. But nothing happens if i write to that, so i suggest this is only an internal confirmation
My understanding of the api documentation ist, that it is something native of c#/.net? maybe a function of some kind, to raise reactions on events?
This answer is valid for TIA 16 with Openness API V16.
Confirmations: If a prompt is triggered in TIA Portal that requires a user decision (i.e. has more than one button), ConfirmationEvent is raised, and it definitely happens prior to any decision being made by the user.
Set IsHandled, then set the Result value. That's all you need to do.
private static void Tiap_Confirmation(object sender, ConfirmationEventArgs e)
{
//signal to TIA Portal that the event is handled
e.IsHandled = true;
//handle the various events
if (CONDITIONS_FOR_CHOOSING_YES)
e.Result = ConfirmationResult.Yes;
if (CONDITIONS_FOR_CHOOSING_CANCEL)
e.Result = ConfirmationResult.Cancel;
...
}
Notifications: NotificationEvent is only raised for prompts that have one button. The example below is for a .NET Framework console application.
using Siemens.Engineering;
using System;
using System.Linq;
using System.Threading;
namespace OpennessConsoleTests
{
class Program
{
static void Main(string[] args)
{
//attach to the first tia portal process found
TiaPortal tiap = TiaPortal.GetProcesses().First().Attach();
//subscribe to confirmation event
tiap.Notification += Tiap_Notification;
//pause
Console.WriteLine("Waiting for events. Press Ctrl+C to quit");
//sleep indefinitely. User must ctrl+C out of this
Thread.Sleep(Timeout.Infinite);
}
private static void Tiap_Notification(object sender, NotificationEventArgs e)
{
e.IsHandled = true;
Console.WriteLine("*****Notification*****");
Console.WriteLine("Caption: " + e.Caption);
Console.WriteLine("Text: " + e.Text);
Console.WriteLine("DetailText: " + e.DetailText);
}
}
}
An important note: According to my testing, some prompts do not raise an event even if subscribed, for example "Subfolder already exists" when extracting an archive. This puts TIA Portal into a locked state until you stop your application.
I think it's just a (not optimal) translation into German. What they mean is you need to set a field in the event args you got. This is a normal pattern in .NET.
Something like this (don't have the library for syntax check but you should get what I mean):
private static void TiaPortal_Confirmation(object sender, ConfirmationEventArgs e)
{
// do your thing, open a confirmation dialog or something, then:
e.Result = Choices.OK;
}
Looking to create a Hot Custom hot reload feature. I need to create an Event They should be able to listen to the Save command. Assume there are two projects in the
same solution.
Solution:
Project A
Class test
Project B
When I change something inside the project A class test and after I used Ctrl+s it should trigger a method inside Project B. I want to listen to the File save the event in the project A Test Class. is there is any way to do this.
I was tried out the Both scenario
Try method 1:-
public virtual event EnvDTE._dispDocumentEvents_DocumentSavedEventHandler DocumentSaved;
public EnvDTE.DTE DTE { get; }
private EnvDTE.Document document;
document = DTE.ActiveDocument;
DocumentSaved?.Invoke(document);
here I am getting a Null reference error. In this case, I am not sure whether I am passing the right Document to invoke the events.
Second was the
using (var filewatcher = new FileSystemWatcher(fullpath))
{
// filewatcher.IncludeSubdirectories = false;
filewatcher.InternalBufferSize = 32768;
filewatcher.Filter = "*.cs";
filewatcher.NotifyFilter = NotifyFilters.LastWrite;
filewatcher.EnableRaisingEvents = true;
filewatcher.Changed += FileChanged;
Console.ReadLine();
}
private void FileChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"File Changed:{e.Name}-path{e.FullPath}");
}
this way I was able to listen to the save command if that file change outside the Visual studio. But when trying to watch the change inside Vs FileSystemWatcher could not able to catch the File modification.
You can subscribe to the DocumentSaved event like this:
events = DTE.Events;
documentEvents = events.DocumentEvents;
documentEvents.DocumentSaved += OnDocumentSaved;
Where OnDocumentSaved is your handler.
I'm trying to add background music to my WPF program. I also want additional sounds to happen "over" the background music. I tried using a SoundPlayer however, this could only play one piece of audio at once.
I am now trying to use MediaPlayer but I cannot get any audio to play. Here is my code:
In my ShellViewModel I start the background music:
Sounds.StartBackgroundMusic()
In my sounds class I have the following:
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri("pack://application:,,,/Assets/Sounds/backgroundmusic.wav"));
_backgroundMusic.MediaEnded += new EventHandler (BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
Since I want the background music to loop continuously, I used the answer in this question to add the BackgroundMusic_Ended event. Can someone please help shed some light on why my audio isn't playing?
I tried to reproduce the problem but it worked as expected.
I created a new WPF application in Visual Studio and used the following code in MainWindow.xaml.cs:
using System;
using System.Windows;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public MainWindow()
{
InitializeComponent();
StartBackgroundMusic();
}
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri(#"C:\<path-to-sound-file>\music.wav"));
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
}
}
Did you try to use a "regular" file path to load a sound file instead of "pack://..."? When I used the wrong path I didn't get any sound and there was no error message or exception.
Since I couldn't use MediaPlayer to play embedded resources and SoundPlayer can only play one sound at a time, I used a combination of them and saved the embedded background music resource to disk so that MediaPlayer could play it. I make a blog about it here
Heres what I did:
I set up my SoundPlayer as this was the simplest one of the two. I created a new SoundPlayer object using the embedded resource
private static readonly SoundPlayer _soundOne = new SoundPlayer(WPF.Properties.Resources.soundOne);
Now the MediaPlayer. I make sure that my audio file is set as an Embedded Resource under the Build Actions in the file’s properties in Visual Studio. Now that we have done this, we can create the method for saving the embedded WAV file to the %temp% location on disk:
public static void SaveMusicToDisk(){
//This sets up a new temporary file in the %temp% location called "backgroundmusic.wav"
using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundmusic.wav")){
//This them looks into the assembly and finds the embedded resource
//inside the WPF project, under the assets folder
//under the sounds folder called backgroundmusic.wav
//PLEASE NOTE: this will be different to you
Assembly.GetExecutingAssembly().GetManifestResourceStream("WPF.Assets.Sounds.backgroundmusic.wav").CopyTo(fileStream);
}
}
We play this by creating a new MediaPlayer object and using the temp file location to play the audio:
//Create a new MediaPlayer object
private static readonly MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic(){
//Open the temp WAV file saved in the temp location and called "backgroundmusic.wav"
_backgroundMusic.Open(new Uri(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav")));
//Add an event handler for when the media has ended, this way
//the music can be played on a loop
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
//Start the music playing
_backgroundMusic.Play();
}
My BackgroundMusic_Ended method looks like this and just makes sure that the music is always restarted once it has finished:
private static void BackgroundMusic_Ended(object sender, EventArgs e){
//Set the music back to the beginning
_backgroundMusic.Position = TimeSpan.Zro;
//Play the music
_backgroundMusic.Play();
}
Then I just had to worry about disposing of the objects and cleaning up the temp file when the program is closing.
All these comes from the idea that i want to use the SerialPort class in .Net , but the only way is by calling dll . Because i can only get interfaces from the program calling this dll. mycode is below.
i wrote a class about serialport,
public class CommClass
{
public SerialPort _port;
private string _receivedText;
public string receivedText
{
get { return _receivedText; }
set
{
_receivedText = value;
}
}
public CommClass(string _pname)
{
portList = SerialPort.GetPortNames();
_port = new SerialPort(portList[0]);
if (portList.Length < 1)
_port= null;
else
{
if(portList.Contains(_pname.ToUpper()))
{
_port = new SerialPort(_pname);
_port.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
}
}
}
private void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string indata = _port.ReadExisting();
receivedText = indata;
}
}
from Bytestoread i can see there r data coming in and i can get data from port.ReadExisting(), but receivedText did not change ,it did not hit the SerialDataReceived event . Is my way wrong?any suggestion?thanks
i created a dll from CommClass ,then i call it in my winform program which has a button and a textbox . Clicking the button , then i initialize the port
public Form1()
{
InitializeComponent();
}
public CommClass mycom;
private void button1_Click(object sender, EventArgs e)
{
mycom = new CommClass("com3");
mycom._port.Open();
textbox.Text=mycom.receivedText;//i add a breakpoint at this line ,
}
when hitting it , i check mycom._port.PortName is "com3", its IsOpen() is "Open" , i use virtual port to send data . i send "1111",then check the mycom._port.BytestoRead is 4, and mycom._port.ReadExisting() is "1111", but mycom.receivedText is null. My puzzle is that i have no idea when the data is coming . How to use the DataReceived event in my winform without code "using System.Io.Ports",just with reference CommClass.dll. Did i make it clear? Thanks for help.
mycom._port.Open();
textbox.Text=mycom.receivedText;//i add a breakpoint at this line ,
That code cannot work, it is a threading race bug. The DataReceived event does not fire instantly after you open the port. It will take a microsecond or so, give or take. A threadpool thread has to get started to fire the event. And of course the device actually has to send something, they usually only do so when you transmit something first.
Which clearly did not happen, your DataReceived event handler has a bug as well. It is not allowed to update the Text property of a control in that event since it runs on a worker thread. Your program will bomb with an InvalidOperationException.
You'll have to write something like this instead:
private void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string indata = _port.ReadExisting();
this.BeginInvoke(new Action(() => {
textbox.AppendText(indata);
}));
}
With the additional stipulation that you must not leave it this way, updating the Text property of a TextBox and making it visible on the screen is an expensive operation that's going to turn your user interface catatonic when the device starts transmitting data at a high rate.
I have an API (dll) that collects stock ticks via an event mechanism. Such as below:
...
using MT4API;
public partial class Blue : Form
{
...
public Blue()
{
...
string symbol = "GBPUSD";
MT4DDE dde = new MT4DDE("");
dde.OnQuote += new System.EventHandler<QuoteEventArgs>(MT_OnQuote);
dde.Connect();
dde.Subscribe(symbol);
....
The idea is that on each chart tick I get an event. here is the event handler code:
private static void MT_OnQuote(object sender, QuoteEventArgs args)
{
GlobalClass.Ask = args.Ask;
GlobalClass.Bid = args.Bid;
// I have back ground worker code that updatestables from the global class
}
This all works fine. So long as I do not touch any other buttons on the form UI. As soon as I click a button on the form of the UI... I no longer receive events from my API, the UI application functions normally, but with no data from the API.
Why do events from the UI stop any further events coming from the API event?
Any idea whats going on here? Or suggestions how to design this?
Does the same problem occur if you comment out your code that updates the tables from the global object? and if you comment out the background worker?
It would be a good idea to distinguish if the event stops being fired just after you press some button on the UI, or if it stops being fired only after some line of code you wrote is being executed.
In order to be able to help you, we would need to know how the event on the MT4DDE class is triggered.
If you have the code for this class, posting it would help.
If you don't you may want to use a tool such as Reflector to decompile the assembly into C# and see what the MT4DDE class is doing that might cause it to stop invoking the event.
In addition, if you are doing anything related to background threads, or if you're doing anything unusual with your application's main message loop, it would be a good idea to mention it here.
I have tried to use the invoke command, it works, but after a few events it stops...here is the code isolated:
using MT4API;
namespace WindowsFormsApplication1
{
public delegate void UpdateTextCallback(double ask, double bid);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string symbol = "GBPUSD";
MT4DDE dde = new MT4DDE("");
dde.OnQuote += new EventHandler<QuoteEventArgs>(MT_OnQuote);
dde.Connect();
dde.Subscribe(symbol);
}
private void updateTickDisplay(double ask, double bid)
{
textBox1.Text = ask.ToString();
textBox2.Text = bid.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void MT_OnQuote(object sender, QuoteEventArgs args)
{
BeginInvoke(new UpdateTextCallback(this.updateTickDisplay),
new object[] { args.Ask, args.Bid });
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox3.Text = textBox1.Text;
}
}
}
The only difference from the real code is that I am using a data grid....as opposed to a text field. But it is clear that the UI blocks somehow the new events. It is strange that I get about 5 to 10 events and then it just stops. Strange. Any ideas on a differnet design?