I am trying to Send Apple Push Notification. And, only ChannelCreated event gets called at my end, and not NotificationFailed or NotificationSent. Also,Notification does not gets sent to that specific Apple Device. I have also run telnet command to fix this issue, but in vain.
public static void SendApplePushNotification(string DeviceToken, String PostData)
{
try
{
string AppleapiPassKey = ConfigurationManager.AppSettings["ApplePushPassword"];
//AppleapiPassKey = string.Empty;
var push = new PushBroker();
push.OnNotificationSent += NotificationSent;
push.OnChannelException += ChannelException;
push.OnServiceException += ServiceException;
push.OnNotificationFailed += NotificationFailed;
push.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
push.OnDeviceSubscriptionChanged += DeviceSubscriptionChanged;
push.OnChannelCreated += ChannelCreated;
push.OnChannelDestroyed += ChannelDestroyed;
var appleCert = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin/private_key_noenc.p12"));
//push.RegisterAppleService(new ApplePushChannelSettings(true,appleCert, AppleapiPassKey)); //Extension method
push.RegisterAppleService(new ApplePushChannelSettings(appleCert, AppleapiPassKey)); //Extension method
var message = new Message() { ChainId = 12, CreatedDate = DateTime.Now, Message1 = "hi how are you" };
push.QueueNotification(new AppleNotification()
.ForDeviceToken(DeviceToken)
.WithAlert(PostData)
.WithSound("Default")
//.WithCustomItem("content-available", message)
//.WithContentAvailable(1)
);
//push.StopAllServices(true);
}
catch (Exception ex)
{
LogError.LogErrorToFile(ex);
}
}
public static void DeviceSubscriptionChanged(object sender,
string oldSubscriptionId, string newSubscriptionId, INotification notification)
{
}
public static void NotificationSent(object sender, INotification notification)
{
}
public static void NotificationFailed(object sender,
INotification notification, Exception notificationFailureException)
{
}
public static void ChannelException
(object sender, IPushChannel channel, Exception exception)
{
}
public static void ServiceException(object sender, Exception exception)
{
}
public static void DeviceSubscriptionExpired(object sender,
string expiredDeviceSubscriptionId,
DateTime timestamp, INotification notification)
{
}
public static void ChannelDestroyed(object sender)
{
}
public static void ChannelCreated(object sender, IPushChannel pushChannel)
{
}
Related
I am trying to transcribe a WAV file and return the text, but it stopped immediately when I start working
I have a button, that when I click it, will call this method, and it supposedly returns me the text of the wav file, but as you can see from the code, I have a Dbug.WriteLine in the start and the stop, and it will print stop immediately
public List<char> Letters { get; set; }
public StringBuilder Builder { get; set; }
public AzureTranscriptionService() {
Letters = new List<char>();
Builder = new StringBuilder();
}
public async Task<string> ConvertToTextAsync(
string FilePath,
string Language,
string WordDocName) {
//Configure speech service
var config = SpeechConfig.FromSubscription
(ConstantsHelpers.AZURE_KEY,
ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = Language;
//Configure speech recognition
var stopRecognition = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput
(FilePath);
{
using var speechRecognizer =
new SpeechRecognizer(config, audioConfig);
speechRecognizer.Recognized += (sender, e) => {
if (e.Result.Reason == ResultReason.RecognizedSpeech) {
foreach (var c in e.Result.Text) {
Letters.Add(c);
}
}
};
speechRecognizer.SessionStarted += (sender, e) => {
Debug.WriteLine("------> Started");
};
speechRecognizer.SessionStopped += (sender, e) => {
Debug.WriteLine("Stop");
foreach (var item in Letters) {
Builder.Append(item);
}
};
speechRecognizer.Recognizing += (sender, e) => {
Debug.WriteLine(e.Result.Text);
stopRecognition.TrySetResult(0);
};
await speechRecognizer.StartContinuousRecognitionAsync();
// Waits for completion. Use Task.WaitAny to keep the task rooted.
await Task.WhenAny(new[] { stopRecognition.Task });
return Builder.ToString();
}
}
}
}
Update
I tried to change the code to this
private TaskCompletionSource<string>? SpeechRecognitionCompletionSource { get; set; }
private StringBuilder? RecognizedSpeechTextBuilder { get; set; } = new StringBuilder();
private SpeechRecognizer? SpeechRecognizer { get; set; }
public async Task<string> ConvertToTextAsync(string filePath,
string language,
string wordDocName) {
// Configure speech service
var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = language;
// Configure speech recognition
this.SpeechRecognitionCompletionSource = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput(filePath);
using (SpeechRecognizer = new SpeechRecognizer(config, audioConfig)) {
SpeechRecognizer.SessionStarted += OnSessionStarted!;
SpeechRecognizer.SessionStopped += OnSessionStopped!;
SpeechRecognizer.Recognizing += OnRecognizing!;
SpeechRecognizer.Recognized += OnRecognized!;
await this.SpeechRecognizer.StartContinuousRecognitionAsync();
// Wait for the 'SpeechRecognizer.StopContinuousRecognitionAsync' call
// before returning the result string.
// In this case, 'SpeechRecognizer.StopContinuousRecognitionAsync'
// is called from a Button.Click event handler.
return await SpeechRecognitionCompletionSource.Task;
}
}
// Stop speech recognition when the user clicks a button
private async void OnStopButtonClicked(object sender, RoutedEventArgs e) {
await SpeechRecognizer!.StopContinuousRecognitionAsync();
}
private void OnSessionStarted(object sender, SessionEventArgs e) {
Debug.WriteLine("------> Started");
}
private void OnSessionStopped(object sender, SessionEventArgs e) {
Debug.WriteLine("Stop");
SpeechRecognitionCompletionSource!.TrySetResult(RecognizedSpeechTextBuilder!.ToString());
}
private void OnRecognizing(object sender, SpeechRecognitionEventArgs e) {
Debug.WriteLine(e.Result.Text);
}
private void OnRecognized(object sender, SpeechRecognitionEventArgs e) {
if (e.Result.Reason != ResultReason.RecognizedSpeech) {
return;
}
foreach (var speechText in e.Result.Text) {
this.RecognizedSpeechTextBuilder!.Append(speechText);
}
}
}
}
and then I call this method in here'
private async void StartAction(object obj) {
IsBusy = true;
CanShow = Visibility.Visible;
var FileWithoutExtension = Path.GetFileNameWithoutExtension
(FilePath);
var AudioPath = FolderHelper.CreateFolder(ConstantsHelpers.AUDIO);
var DocumentPath = FolderHelper.CreateFolder();
var AudioFileNamePath = Path.Combine(AudioPath, $"{FileWithoutExtension}{ConstantsHelpers.WAV}");
var ConvertedAudioPath = AudioHelper.Converter(FilePath!, AudioFileNamePath);
var DocumentName = Path.Combine(DocumentPath, $"{FileWithoutExtension}{ConstantsHelpers.DOCX}");
var res = await AzureTranscription.ConvertToTextAsync(ConvertedAudioPath,
SelectedItem, DocumentName);
IsBusy = false;
StartCommand.RaiseCanExecuteChanged();
CanShow = Visibility.Hidden;
}
Update
I manage to get it working, but I need to return the text to my MainViewModel
public async Task ConvertToTextAsync(string FilePath, string FileName) {
List<char> Characers = new();
StringBuilder builder = new();
//Configure speech service
var config = SpeechConfig.FromSubscription
(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
//Configure speech recognition
var taskCompleteionSource = new TaskCompletionSource<int>();
using var audioConfig = AudioConfig.FromWavFileInput(FilePath);
if (!string.IsNullOrEmpty(FileName)) {
using var speechRecognizer = new SpeechRecognizer(config, audioConfig);
speechRecognizer.Recognized += (sender, e) => {
if (e.Result.Reason == ResultReason.RecognizedSpeech) {
foreach (var item in e.Result.Text) {
Characers.Add(item);
}
}
};
speechRecognizer.SessionStarted += (sender, e) => {
Debug.WriteLine("--------> started");
};
speechRecognizer.SessionStopped += (sender, e) => {
Debug.WriteLine("-----------> stooped");
foreach (var item in Characers) {
builder.Append(item);
}
Debug.WriteLine(builder.ToString());
};
await speechRecognizer.StartContinuousRecognitionAsync()
.ConfigureAwait(false);
Task.WaitAny(new[] { taskCompleteionSource.Task });
await speechRecognizer.StopContinuousRecognitionAsync()
.ConfigureAwait(false);
}
return builder.ToString();
}
}
}
I seems like you are returning from the ConvertToTextAsync method prematurely. This is because you are transitioning the TaskCompletionSource too early. As a consequence you leave the method and therefore the using scope of the SpeechRecognizer, which as a result will stop the continuous speech recognition.
The idea is to complete the TaskCompletionSource not before the SpeechRecognizer has stopped (by calling the SpeechRecognizer.StopContinuousRecognitionAsync method). You can achieve this by calling TaskCompletionSource.TrySetResult from the SpeechRecognizer.SessionStopped event handler:
private TaskCompletionSource<string> SpeechRecognitionCompletionSource { get; set; }
private StringBuilder RecognizedSpeechTextBuilder { get; set; }
private SpeechRecognizer SpeechRecognizer { get; set; }
public async Task<string> ConvertToTextAsync(string filePath,
string language,
string wordDocName)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(filePath);
}
// Configure speech service
var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = language;
// Configure speech recognition
this.SpeechRecognitionCompletionSource = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput(filePath);
using (this.SpeechRecognizer = new SpeechRecognizer(config, audioConfig))
{
this.SpeechRecognizer.SessionStarted += OnSessionStarted;
this.SpeechRecognizer.SessionStopped += OnSessionStopped;
this.SpeechRecognizer.Recognizing += OnRecognizing;
this.SpeechRecognizer.Recognized += OnRecognized;
this.SpeechRecognizer.Recognized += OnCanceled;
await this.SpeechRecognizer.StartContinuousRecognitionAsync();
// Wait for the 'SpeechRecognizer.StopContinuousRecognitionAsync' call
// before returning the result string.
// In this case, 'SpeechRecognizer.StopContinuousRecognitionAsync'
// is called from a Button.Click event handler.
return await this.SpeechRecognitionCompletionSource.Task;
}
}
// Stop speech recognition when the user clicks a button
private async void OnStopButtonClicked(object sender, RoutedEventArgs e)
{
await this.SpeechRecognizer.StopContinuousRecognitionAsync();
}
private void OnSessionStarted(object sender, SessionEventArgs e)
{
Debug.WriteLine("------> Started");
}
private void OnSessionStopped(object sender, SessionEventArgs e)
{
Debug.WriteLine("Stop");
this.SpeechRecognitionCompletionSource.TrySetResult(this.RecognizedSpeechTextBuilder.ToString());
}
private void OnRecognizing(object sender, SpeechRecognitionEventArgs e)
{
Debug.WriteLine(e.Result.Text);
}
private void OnRecognized(object sender, SpeechRecognitionEventArgs e)
{
if (e.Result.Reason != ResultReason.RecognizedSpeech)
{
return;
}
foreach (string speechText in e.Result.Text)
{
this.RecognizedSpeechTextBuilder.Append(speechText);
}
}
private void OnCanceled(object sender, SpeechRecognitionCanceledEventArgs e)
{
if(e.Reason == CancellationReason.EndOfStream)
{
await this.SpeechRecognizer.StopContinuousRecognitionAsync();
}
}
I am writing a program which is supposed to detect when a USB serial device is plugged in and then log on to the new com port. The code below works wonderfully, but I have noticed in debugging the code and stepping through it that the event handler "DetectChange" fires twice. I'm not sure that this is normal, or an action of the debugger.
In any case, the code works, but I am new at event handling and I would like to make sure that I am not going to cause any issues as I add more code to actually read and write from the serial port.
(I got some of this code from stackoverflow, but I have misplaced my paper with names for attribution. If you see your code below, my heartfelt thanks.)
using System;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Management;
using System.Threading;
namespace SerialTest
{
public partial class Form1 : Form
{
SerialMethods serialMethods = new SerialMethods();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
loadCmdBox();
}
private void CmdBoxPort_SelectedIndexChanged(object sender, EventArgs e)
{
handleComPort();
}
private void handleComPort()
{
// Set the right port for the selected item.
// The portname is based on the "COMx" part of the string (SelectedItem)
string item = CmdBoxPort.SelectedItem.ToString();
// Search for the expression "(COM" in the "selectedItem" string
if (item.Contains("(COM"))
{
// Get the index number where "(COM" starts in the string
int indexOfCom = item.IndexOf("(COM");
// Set PortName to COMx based on the expression in the "selectedItem" string
// It automatically gets the correct length of the COMx expression to make sure
// that also a COM10, COM11 and so on is working properly.
string PortName = item.Substring(indexOfCom + 1, item.Length - indexOfCom - 2);
if (serialMethods._serialPort.IsOpen)
{
serialMethods._serialPort.Close();
serialMethods.Connect(PortName);
label5.Text = "Active Port: " + PortName;
}
else
{
serialMethods.Connect(PortName);
label5.Text = PortName;
}
}
else
return;
}
private void loadCmdBox()
{
// Get all serial (COM)-ports you can see in the devicemanager
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\cimv2",
"SELECT * FROM Win32_PnPEntity WHERE ClassGuid=\"{4d36e978-e325-11ce-bfc1-08002be10318}\"");
// Sort the items in the combobox
CmdBoxPort.Sorted = true;
// Add all available (COM)-ports to the combobox
foreach (System.Management.ManagementObject queryObj in searcher.Get().Cast<ManagementObject>())
{
CmdBoxPort.Items.Add(queryObj["Caption"]);
}
SerialPortService.PortsChanged += (sender1, changedArgs) => DetectChange(changedArgs.EventType);
label2.Text = "";
label3.Text = "";
label4.Text = "";
}
protected Task<Task> getSerPorts()
{
CmdBoxPort.Text = "";
CmdBoxPort.Update();
if (!String.IsNullOrEmpty(CmdBoxPort.Text))
{
handleComPort();
return Task.FromResult(Task.CompletedTask);
}
else
{
loadCmdBox();
return Task.FromResult(Task.CompletedTask);
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
SerialPortService.CleanUp();
this.Close();
}
private void RefreshButton_Click(object sender, EventArgs e)
{
refresh();
}
protected Task<Task> refresh()
{
label2.Text = "";
label3.Text = "";
label4.Text = "";
CmdBoxPort.Items.Clear();
getSerPorts();
return Task.FromResult(Task.CompletedTask);
}
protected virtual void DetectChange(EventType changedArgs)
{
if (changedArgs == EventType.Insertion)
{
try
{
Task tr = (Task)Invoke(new Action( () => { getSerPorts(); }));
Task rr = (Task)Invoke(new Action(() => { refresh(); }));
}
catch (Exception ex) { MessageBox.Show("Exception at insertion invoke method " + ex, "Exception", MessageBoxButtons.OK); }
}
else if (changedArgs == EventType.Removal)
{
try
{
Task tr = (Task)Invoke(new Action( () => { getSerPorts(); }));
Task rr = (Task)Invoke(new Action(() => { refresh(); }));
}
catch (Exception ex) { MessageBox.Show("Exception at removal invoke method " + ex, "Exception", MessageBoxButtons.OK); }
}
return;
}
}
public static class SerialPortService
{
private static SerialPort _serialPort;
private static string[] _serialPorts;
private static ManagementEventWatcher arrival;
private static ManagementEventWatcher removal;
private static readonly SerialMethods SD = new SerialMethods();
static SerialPortService()
{
_serialPorts = SerialPort.GetPortNames();
MonitorDeviceChanges();
}
public static void CleanUp()
{
arrival.Stop();
removal.Stop();
}
public static event EventHandler<PortsChangedArgs> PortsChanged;
private static void MonitorDeviceChanges()
{
try
{
var deviceArrivalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var deviceRemovalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
arrival = new ManagementEventWatcher(deviceArrivalQuery);
removal = new ManagementEventWatcher(deviceRemovalQuery);
arrival.EventArrived += (o, args) => RaisePortsChangedIfNecessary(EventType.Insertion);
removal.EventArrived += (sender, eventArgs) => RaisePortsChangedIfNecessary(EventType.Removal);
// Start listening for events
arrival.Start();
removal.Start();
}
catch (ManagementException err)
{
MessageBox.Show("Management exception = " + err, "Info", MessageBoxButtons.OK);
}
}
private static void RaisePortsChangedIfNecessary(EventType eventType)
{
lock (_serialPorts)
{
var availableSerialPorts = SerialPort.GetPortNames();
if (eventType == EventType.Insertion)
{
var added = availableSerialPorts.Except(_serialPorts).ToArray();
_serialPorts = availableSerialPorts;
PortsChanged.Raise(null, new PortsChangedArgs(eventType, added));
}
else if (eventType == EventType.Removal)
{
var removed = _serialPorts.Except(availableSerialPorts).ToArray();
_serialPorts = availableSerialPorts;
PortsChanged.Raise(null, new PortsChangedArgs(eventType, removed));
}
}
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
{
handler?.Invoke(sender, args);
}
}
public enum EventType
{
Insertion,
Removal,
}
public class PortsChangedArgs : EventArgs
{
private readonly EventType _eventType;
private readonly string[] _serialPorts;
public PortsChangedArgs(EventType eventType, string[] serialPorts)
{
_eventType = eventType;
_serialPorts = serialPorts;
}
public string[] SerialPorts => _serialPorts;
public EventType EventType => _eventType;
}
}
Just took a short look at this. It seems like getSerPorts() will always execute loadCmdBox() (CmdBoxPort.Text = ""; ... if (!String.IsNullOrEmpty(CmdBoxPort.Text))) that will attach a new event handler (previous attached event handlers will not be removed by attaching a new one).
You should either remove the existing event handler befor attaching a new one or only attach the event handler once.
I'm trying to fetch emails as soon as they arrive in my inbox using MailSystem.NET library. Everything works fine IMAP client gets connected but my NewMessageReceived event is never fired.
Please Help
Below is the code:
public static Imap4Client _imap = new Imap4Client();
public string SenderEmailAddress = System.Configuration.ConfigurationManager.AppSettings["EmailAddress"];
public string SenderEmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"];
public static Mailbox inbox = new Mailbox();
protected void Application_Start()
{
var worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(StartIdleProcess);
if (worker.IsBusy)
worker.CancelAsync();
worker.RunWorkerAsync();
}
private void StartIdleProcess(object sender, DoWorkEventArgs e)
{
try
{
if (_imap != null && _imap.IsConnected)
{
_imap.StopIdle();
_imap.Disconnect();
}
_imap = new Imap4Client();
_imap.NewMessageReceived += new NewMessageReceivedEventHandler(NewMessageReceived);
_imap.ConnectSsl("imap.gmail.com", 993);
_imap.Login(SenderEmailAddress, SenderEmailPassword);
inbox = _imap.SelectMailbox("inbox");
int[] ids = inbox.Search("UNSEEN");
inbox.Subscribe();
_imap.StartIdle();
}
catch (Exception ex)
{
}
}
public static void NewMessageReceived(object source, NewMessageReceivedEventArgs e)
{
int offset = e.MessageCount - 2;
Message message = inbox.Fetch.MessageObject(offset);
Debug.WriteLine("message subject: " + message.Subject);
// Do something with the source...
_imap.StopIdle();
}
I can't tell you the exact reason but it seems that interacting with the imapclient from the NewMessageReceived event just doesn't work.
In NewMessageReceived call _imap.StopIdle() then continue in your main execution flow and restart idle. Then use a boolean to drop out of the loop entirely.
private bool _stop = false;
private void StartIdle(object sender, DoWorkEventArgs e)
{
//Setup client
_imap = new Imap4Client();
_imap.NewMessageReceived += new NewMessageReceivedEventHandler(NewMessageReceived);
StartRepeatExecution();
}
public void StartRepeatExecution()
{
_imap.StartIdle();
if(_stop) return;
//Handle your new messages here! dummy code
var mailBox = _imap.SelectMailBox("inbox");
var messages = mailBox.SearchParse("").Last();
StartRepeatExecution();
}
public static void NewMessageReceived(object source, NewMessageReceivedEventArgs e)
{
//StopIdle will return to where _imap.StartIdle() was called.
_imap.StopIdle();
}
public void StopRepeatExecution()
{
_stop = true;
}
I tried to send Apple push notification with PushSharp library like that:
public class Push
{
private readonly PushBroker _push;
private static Push _instance;
public static Push Instance
{
get { return _instance ?? (_instance = new Push()); }
}
public Push()
{
_push = new PushBroker();
_push.OnNotificationSent += new NotificationSentDelegate(_push_OnNotificationSent);
_push.OnNotificationFailed += new NotificationFailedDelegate(_push_OnNotificationFailed);
_push.OnServiceException += new ServiceExceptionDelegate(_push_OnServiceException);
_push.OnChannelCreated += new ChannelCreatedDelegate(_push_OnChannelCreated);
_push.OnChannelDestroyed += new ChannelDestroyedDelegate(_push_OnChannelDestroyed);
_push.OnChannelException += new ChannelExceptionDelegate(_push_OnChannelException);
_push.OnNotificationRequeue += new NotificationRequeueDelegate(_push_OnNotificationRequeue);
_push.RegisterAppleService(new ApplePushChannelSettings(false, File.ReadAllBytes(#"C:\PathToCertificate\Name.p12"), "***"), "myAppId", new PushServiceSettings()
{
Channels = 1,
AutoScaleChannels = false
});
}
void _push_OnNotificationRequeue(object sender, NotificationRequeueEventArgs e)
{
Debug.Print("requeue");
}
void _push_OnChannelException(object sender, IPushChannel pushChannel, Exception error)
{
Debug.Print("channel exception");
}
void _push_OnChannelDestroyed(object sender)
{
Debug.Print("channel destroyed");
}
void _push_OnChannelCreated(object sender, IPushChannel pushChannel)
{
Debug.Print("channel created");
}
void _push_OnServiceException(object sender, System.Exception error)
{
Debug.Print("service exception");
}
void _push_OnNotificationFailed(object sender, INotification notification, System.Exception error)
{
Debug.Print("failed");
}
void _push_OnNotificationSent(object sender, INotification notification)
{
Debug.Print("sent");
}
public void Send(Notification notification)
{
_push.QueueNotification(notification);
_push.StopAllServices("biz.sintek.Rotapost", true);
}
public void SendAppleNotification(string deviceToken, string text)
{
Send(new AppleNotification()
.ForDeviceToken(deviceToken)
.WithAlert(text)
.WithSound("default"));
}
}
I'm calling SendAppleNotification method. It returns in no time but no exceptions throwed, no events called, no notifications sent and no notifications received.
I am using developer push certificate converted to .p12 format.
Double checked provisioning profile.
QueueNotification method of PushBroker class is generic. It using generic type parameter to identify which service to use for notification send.
Solution is to pass new AppleNotification()... directly to the QueueNotification
I have a working solution that reports progress & text to a progress bar and a label on the applications's main form. I have now moved my worker methods to a class to they are accessible across multiple forms etc.
Within the worker methods are BW.ReportProgress() statements that push back the progress and text to the BackgroundWorker in the main form.
To give a better idea here is the file layout:
MainScreen.cs
List repSelected = new List();
XMLandRar xXMLandRar = new XMLandRar();
private void Rarbtn_Click(object sender, EventArgs e)
{
GetReps();
//Run worker
if (!CreateRarBW.IsBusy)
{
CreateRarBW.RunWorkerAsync();
}
}
//Worker
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
xXMLandRar.RarFiles(repSelected);
}
//Progress reporting
private void CreateRarBW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progBar.Value = e.ProgressPercentage;
Statuslbl.Text = e.UserState.ToString();
}
Then my newly created Class that encompasses all of the worker methods and is to push progress to the main form.
XMLandRar.cs
public class XMLandRar
{
public void RarFiles(List repSelected)
{
int step = 100 / repSelected.Count();
int i = 0;
//Iterate through list and run rar for each
foreach (string rep in repSelected)
{
CreateRarBW.ReportProgress(i, "Raring files for " + rep);
DirectoryExists(rep);
ProcessRunner(rep);
i += step;
CreateRarBW.ReportProgress(i, "Raring files for " + rep);
}
}
}
The problem I am having is that in the XMLandRar class the CreateRarBW is not recognised (obviously) - how can I make a ReportProgress call to the BW in the main screen of the application?
Create an event in your XMLandRar class which you could subscribe to.
This way the XMLandRar class doesn't need to know or care about the UI or progressbar, it only cares about sending a message if anyone would listen. And there can also be more than one subscriber (let's say if you want to report to the background worker and a log, maybe)
Example:
private void Rarbtn_Click(object sender, EventArgs e)
{
GetReps();
//Run worker
if (!CreateRarBW.IsBusy)
{
// This should be done once, maybe in the contructor. Bind to new event.
xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);
CreateRarBW.RunWorkerAsync();
}
}
protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
{
// Call the UI backgroundworker
CreateRarBW.ReportProgress(e.Percentage, e.Message);
}
public class XMLandRar
{
// Event handler to bind to for reporting progress
public EventHandler<ProgressArgs> ReportProgress;
// Eventargs to contain information to send to the subscriber
public class ProgressArgs : EventArgs
{
public int Percentage { get; set; }
public string Message { get; set; }
}
public void RarFiles(List repSelected)
{
int step = 100 / repSelected.Count();
int i = 0;
//Iterate through list and run rar for each
foreach (string rep in repSelected)
{
// Report progress if somebody is listening (subscribed)
if (ReportProgress != null)
{
ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
}
DirectoryExists(rep);
ProcessRunner(rep);
i += step;
// Report progress if somebody is listening (subscribed)
if (ReportProgress != null)
{
ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
}
}
}
}
The sender object in the DoWork callback is the BackgroundWorker instance which is calling this callback.
This enables to use the instance and add it to your new XMLandRar class.
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker.
xXMLandRar.RarFiles(repSelected, worker);
}
XMLandRar.cs
public class XMLandRar
{
public void RarFiles(List repSelected, BackgroundWorker worker)
{
// ...
}
}
Or you set the BackgroundWorkerinstance as a class property to the XMLandRar.
public class XMLandRar
{
protected BackgroundWorker mWorker;
public XMLandRar(BackgroundWorker worker) {
mWorker = BackgroundWorker;
}
public void RarFiles(List repSelected)
{
// Do something with {mWorker}
}
}
Or as mentioned in the comments, using events in the XMLandRar class.
XMLandRar.cs
public class XmlandRarCompletedEventArgs : EventArgs
{
public readonly bool Finished;
public readonly bool Canceled;
public XmlandRarCompletedEventArgs(bool finished)
{
Finished = finished;
Canceled = !finished;
}
}public class OnXmlandRarUpdateEventArgs : EventArgs
{
public readonly int Percentage;
public readonly string Message;
public XmlandRarCompletedEventArgs(int perc) :
this(perc, "") {
}
public XmlandRarCompletedEventArgs(int perc, string message)
{
Percentage = perc;
Message = message;
}
}
public delegate void OnXmlandRarDoWorkHandler(object o);
public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);
public class XMLandRar
{
public event OnXmlandRarDoWorkHandler OnDoWork;
public event OnXmlandRarUpdateHandler OnUpdate;
public event OnXmlandRarCompletedHandler OnComplete;
public void RarFiles(List repSelected)
{
TriggerDoWork();
int step = 100 / repSelected.Count();
int i = 0;
//Iterate through list and run rar for each
foreach (string rep in repSelected)
{
TriggerUpdate(i, "Raring files for " + rep);
DirectoryExists(rep);
ProcessRunner(rep);
i += step;
TriggerUpdate(i, "Raring files for " + rep);
}
TriggerComplete(true);
}
private void TriggerDoWork()
{
if (OnDoWork != null) {
OnDoWork(this);
}
}
private void TriggerUpdate(perc) {
}
if (OnUpdate != null) {
OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
}
private void TriggerUpdate(perc, string message)
{
if (OnUpdate != null) {
OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
}
}
private void TriggerComplete(bool finished)
{
if (OnComplete != null) {
OnComplete(this, new XmlandRarCompletedEventArgs(finished));
}
}
}
Usage:
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
// Attach events to class
xXMLandRar.OnDoWork += delegate(object o) {
// ...
};
xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args) {
// ...
};
xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args) {
// ...
};
xXMLandRar.RarFiles(repSelected, worker);
}
Hopefully without typos 'cause I'm in the office.
I have fixed errors in the code submitted and cleaned it up... This is a working sample that will help those that maybe couldn't understand the code since it was broken as it was... Although I would like to say that the intent and functionality of the code after it was cleaned up and enhanced is excellent.
This is working code that can get you started in your project for using a backGroundWorker thread for whatever you need.
Just modify this method -
public void RarFiles(List<string> repSelected)
To do whatever work you need. You will also have to modify the arguments you plan on using.. i.e. you may need a DataTable or some custom object...
You can modify the
public class OnXmlandRarUpdateEventArgs : EventArgs
For your needs.. that way when you get a callback.. you can update your main UI form with the changes made to those items..
You may need to do some tweaking.. but you see what i mean..
This is the Form Code.. Don't forget to create a button on the form...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadSample
{
public partial class Form1 : Form
{
List<string> repSelected = new List<string>();
XMLandRar xXMLandRar = new XMLandRar();
BackgroundWorker CreateRarBW = new BackgroundWorker();
public Form1()
{
InitializeComponent();
repSelected = new List<string> { "asdf", "asdfsd", "h;ljj" };
CreateRarBW.DoWork += new DoWorkEventHandler(CreateRarBW_DoWork);
}
private void Rarbtn_Click(object sender, EventArgs e)
{
//GetReps();
//Run worker
if (!CreateRarBW.IsBusy)
{
// This should be done once, maybe in the contructor. Bind to new event.
xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);
CreateRarBW.RunWorkerAsync();
}
}
protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
{
// Call the UI backgroundworker
CreateRarBW.ReportProgress(e.Percentage, e.Message);
}
//private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
//{
// var worker = sender as BackgroundWorker;
// xXMLandRar.RarFiles(repSelected, worker);
//}
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
// Attach events to class
xXMLandRar.OnDoWork += delegate(object o)
{
// ...
MessageBox.Show("Hey ... Something is going on over there in the classLib .. " + o);
};
xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args)
{
// ...
//foreach (object oo in args)
{
MessageBox.Show("Hey ... Something is going on over there in the classLib .. Message is " + args.Message + " and Percentage is " + args.Percentage);
}
};
xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args)
{
MessageBox.Show("Hey ... Something is going on over there in the classLib .. Canceled is " + args.Canceled + " and Finished is " + args.Finished);
// ...
};
xXMLandRar.RarFiles(repSelected);//, worker);
}
}
}
This is the class code. You can just create a class in your current project... Keep in mind that the CreateRarBW object is a BackGroundWorker instance... (Wasn't included above..)
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace ThreadSample
{
public class XmlandRarCompletedEventArgs : EventArgs
{
public readonly bool Finished;
public readonly bool Canceled;
public XmlandRarCompletedEventArgs(bool finished)
{
Finished = finished;
Canceled = !finished;
}
}
public class OnXmlandRarUpdateEventArgs : EventArgs
{
public readonly int Percentage;
public readonly string Message;
public OnXmlandRarUpdateEventArgs(int perc) : this(perc, "")
{
}
public OnXmlandRarUpdateEventArgs(int perc, string message)
{
Percentage = perc;
Message = message;
}
}
public delegate void OnXmlandRarDoWorkHandler(object o);
public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);
public class XMLandRar // : BackgroundWorker
{
// Event handler to bind to for reporting progress
public EventHandler<ProgressArgs> ReportProgress;
// Eventargs to contain information to send to the subscriber
public class ProgressArgs : EventArgs
{
public int Percentage { get; set; }
public string Message { get; set; }
}
public event OnXmlandRarDoWorkHandler OnDoWork;
public event OnXmlandRarUpdateHandler OnUpdate;
public event OnXmlandRarCompleteHandler OnComplete;
public void RarFiles(List<string> repSelected)
{
TriggerDoWork();
int step = 100 / repSelected.Count();
int i = 0;
//Iterate through list and run rar for each
foreach (string rep in repSelected)
{
TriggerUpdate(i, "Raring files for " + rep);
//DirectoryExists(rep);
//ProcessRunner(rep);
i += step;
TriggerUpdate(i, "Raring files for " + rep);
}
TriggerComplete(true);
}
private void TriggerDoWork()
{
if (OnDoWork != null)
{
OnDoWork(this);
}
}
private void TriggerUpdate(int perc)
{
if (OnUpdate != null)
{
OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
}
}
private void TriggerUpdate(int perc, string message)
{
if (OnUpdate != null)
{
OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
}
}
private void TriggerComplete(bool finished)
{
if (OnComplete != null)
{
OnComplete(this, new XmlandRarCompletedEventArgs(finished));
}
}
}
}