I am writing a program that has a FileSystemWatcher. I also have two other methods that I want to run alongside the FSW. But my other methods don't get executed because the program is always at the FSW.
Essentially, I want to have the FileSystemWatcher keep going and be able to perform other actions in my program at the same time.
How can I structure my code to achieve this?
Currently, my code has this structure:
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
// call the FSW
MyFileSystemWatcher(path);
// call another method
AnotherMethod1();
// call another method
AnotherMethod2();
}
//----- file system watcher methods -----//
private static void MyFileSystemWatcher(string path)
{
// code for the file system watcher
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Path = path;
fileSystemWatcher.Created += FileSystemWatcher_Created;
fileSystemWatcher.Renamed += FileSystemWatcher_Renamed;
fileSystemWatcher.Deleted += FileSystemWatcher_Deleted;
fileSystemWatcher.EnableRaisingEvents = true;
}
private static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine("File created: {0}", e.Name);
}
private static void FileSystemWatcher_Renamed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("File renamed: {0}", e.Name);
}
private static void FileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
{
Console.WriteLine("File deleted: {0}", e.Name);
}
//----- end of file system watcher methods -----//
//----- other methods in the program -----//
public static void AnotherMethod1()
{
// code for Method1
}
private static void AnotherMethod2()
{
// code for Method2
}
}
}
Thank you.
Make your method async
private static async Task MyFileSystemWatcher(string path)
{
// code for the file system watcher
}
then
static void Main(string[] args)
{
// call the File System Watcher
var task = MyFileSystemWatcher(path);
// call another method
AnotherMethod1();
// call another method
AnotherMethod2();
}
Alternatively, If you dont want to touch your method (not preferable), then
var task = Task.Run(() => MyFileSystemWatcher(path));
Related
I have a Windows Form application and managed DLL in one solution. DLL contains some time consuming functions during which I wish to update the Form contents (callback from the DLL to the Form with progess updates). I have the following code:
Form code, where I initialize the DLL and give it a callback function in the Initialize method. I also start a separate Thread to periodicly check the message_queue for new messages from the DLL. The DLL function is also called in a separate Thread (non blocking for the UI).
private LibraryDLL library_dll;
private ConcurrentQueue<string> message_queue;
public MainForm()
{
InitializeComponent();
library_dll = new LibraryDLL();
message_queue = new ConcurrentQueue<string>();
library_dll.Initialize(ProcessMessage);
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
string message;
if (message_queue.TryDequeue(out message))
{
PrintMessage(message);
}
}).Start();
}
private void ProcessMessage(string message)
{
message_queue.Enqueue(message);
}
private void PrintMessage(string message)
{
this.Invoke((MethodInvoker)delegate
{
listBox_rows.Items.Add(message);
});
}
private void button_send_Click(object sender, EventArgs e)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
library_dll.DoWork();
}).Start();
}
In DLL code, I use the callback method to report progress:
private CallBack callback;
public delegate void CallBack(string message);
public LibraryDLL() { }
public void Initialize(CallBack callback)
{
this.callback = callback;
}
public void DoWork()
{
callback("working...")
Thread.Sleep(500);
callback("working...")
Thread.Sleep(500);
callback("working...")
Thread.Sleep(500);
}
My problem is, that instead of string "working" appearing every 500ms, it appears 3 times after 1500ms (only after the Thread in which the DoWork method is running ends). I also tried the Invalidate()-Update()-Refresh() sequence in the Form's PrintMessage function, but without any effect.
Thanks for the advice!
EDIT1:
I modified the code to use the BackgroundWorker, however, the problem remains (nothing for 1500ms, than all 3 strings at once).
BackgroundWorker bck_worker;
public MainForm()
{
InitializeComponent();
library_dll = new LibraryDLL();
library_dll.Initialize(bck_worker);
bck_worker = new BackgroundWorker();
bck_worker.ProgressChanged += new ProgressChangedEventHandler(bckWorker_ProgressChanged);
bck_worker.WorkerReportsProgress = true;
bck_worker.WorkerSupportsCancellation = true;
}
private void bckWorker_DoWork(object sender, DoWorkEventArgs e)
{
library_dll.DoWork();
}
private void bckWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
PrintMessage((string)e.UserState);
}
private void button_send_Click(object sender, EventArgs e)
{
bck_worker.DoWork += new DoWorkEventHandler(bckWorker_DoWork);
bck_worker.RunWorkerAsync();
}
private void PrintMessage(string message)
{
listBox_rows.Items.Add(message);
}
And the DLL:
private BackgroundWorker bck_worker;
public LibraryDLL() { }
public void Initialize(BackgroundWorker bck_worker)
{
this.bck_worker = bck_worker;
}
public void DoWork()
{
bck_worker.ReportProgress(25, "working...");
Thread.Sleep(500);
bck_worker.ReportProgress(50, "working...");
Thread.Sleep(500);
bck_worker.ReportProgress(75, "working...");
Thread.Sleep(500);
}
EDIT2:
OK, I now tried to add the Invalidate-Update-Refresh sequence at the end of the PrintMessage function and it finaly works (with the BackgroundWorker approach)!
Use background worker and workers's report progress to update your UI: background worker doc
I am trying to monitor a log file for changes. My code is working, and does everything it should. However, as I want this to run as a windows service and be constantly monitoring I'm not sure of the proper way to set it into a waiting state. Here is what it's doing at the moment.
public static void Main()
{
log_watcher = new FileSystemWatcher();
log_watcher.Path = Path.GetDirectoryName(pathToFile);
log_watcher.Filter = recent_file.Name;
log_watcher.NotifyFilter = NotifyFilters.LastWrite;
log_watcher.Changed += new FileSystemEventHandler(OnChanged);
log_watcher.EnableRaisingEvents = true;
//do rest of stuff OnChanged
while (true)
{
}
}
And then just a simple:
public static void OnChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine("File has changed");
}
What would be a better way in a windows service to do this?
You can start a message pump using Application.Run() from WinForms.
using System.Windows.Forms;
// The class that handles the creation of the application windows
class MyApplicationContext : ApplicationContext {
private MyApplicationContext() {
// Handle the ApplicationExit event to know when the application is exiting.
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
log_watcher = new FileSystemWatcher();
log_watcher.Path = Path.GetDirectoryName(pathToFile);
log_watcher.Filter = recent_file.Name;
log_watcher.NotifyFilter = NotifyFilters.LastWrite;
log_watcher.Changed += new FileSystemEventHandler(OnChanged);
log_watcher.EnableRaisingEvents = true;
}
public static void OnChanged(object sender, FileSystemEventArgs e) {
Console.WriteLine("File has changed");
}
private void OnApplicationExit(object sender, EventArgs e) {
Console.WriteLine("File monitor exited.");
}
[STAThread]
static void Main(string[] args) {
// Create the MyApplicationContext, that derives from ApplicationContext,
// that manages when the application should exit.
MyApplicationContext context = new MyApplicationContext();
// Run the application with the specific context. It will exit when
// all forms are closed.
Application.Run(context);
}
}
See Run(ApplicationContext) on learn.microsoft.com.
I'm building one software integration with one old WPF application. This WPF application have an event handler for drop event:
public void Window_Drop(object sender, DragEventArgs e)
{
// Spaghetti code
}
The Window_Drop event take the dropped file, elaborate it and send the result to a web services.
My goal is use the current logic dropping a file inside a specific folder.
I wrote this code:
Watcher class
public class Watcher
{
public delegate void ActionDelegate(string fileName, string fullPath);
private ActionDelegate Action;
private readonly FileSystemWatcher _watcher;
public Watcher(string path)
{
_watcher = new FileSystemWatcher();
_watcher.Path = path;
_watcher.Created += _watcher_Created;
_watcher.EnableRaisingEvents = true;
}
public void SubscribeOnCreate(ActionDelegate action)
{
Action = action;
}
private void _watcher_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine("Creato " + e.Name);
Action(e.Name, e.FullPath, string.Empty);
}
}
}
App.cs
public partial class App : Application, ISingleInstanceApp
{
private Watcher _watcher;
public App()
{
_watcher = new Watcher(#"C:\Users\Administrator\Desktop\Monitoraggio");
_watcher.SubscribeOnCreate(LoadFile);
}
private void LoadFile(string fileName, string fullPath)
{
var droppedFile = new DragEventArgs(); // How can I build one DragEventArgs object with dropped file?
var currentWindow = MainWindow.AppWindow; // this is a static reference of current MainWindow
a.Window_Drop(this, droppedFile);
}
}
How can I build one vali DragEventArgs manually?
Every suggestion is welcome,
Thanks
You can't create an instance of the DragEventArgs class without using reflection since it has no public constructor defined.
What you should do is to refactor the Window_Drop event handler so that it takes the data that it needs from the DragEventArgs that gets created by the framework and then passes this data to a method of yours that you can also call from your LoadFile method.
So instead of trying to invoke the actual event handler, you call the same method as the event handler calls if you see what I mean.
The other, non-recommended, option would be to use reflection to create an instance of the DragEventArgs class:
Instantiating a constructor with parameters in an internal class with reflection
I have a form with a WebBrowser control, and an extra seperate thread that controls the browser and waits for it to load. Here's a code example:
private void Form1_Load(object sender, EventArgs e){
JobClass.mainAsync();
}
-
public static class JobClass
{
public static void mainAsync()
{
Thread t = new Thread(main);
t.Start();
}
private static void main()
{
Form1 frm = (Form1)Application.OpenForms["Form1"];
WebBrowser wb = frm.webBrowser1;
gotoGoogle(frm, wb);
}
private static void gotoGoogle(Form1 frm, WebBrowser wb)
{
frm.Invoke((MethodInvoker)delegate
{
wb.Navigate("google.com");
string loc = wb.Document.Url.AbsolutePath;
// ... some extra code ...
});
}
private static void gotoYoutube(Form1 frm, WebBrowser wb)
{
frm.Invoke((MethodInvoker)delegate
{
wb.Navigate("youtube.com");
wb.Document.Body.getElementById("...");
// ... some extra code ...
});
}
}
Everything runs fine but as you see, I have to pass the Form1 variable to each method that deals with the browser control, and I have to write frm.Invoke() in all of them, which makes my code less portable and more painful as the code gets bigger.
I was wondering if there's something I could do inside the "main()" method to make the WebBrowser maybe a child of the same thread so I don't have to keep invoking it from the form each time ? If not, how can I just get rid of this ugly invoke thing ?
you can do the following
define an event in your JobClass call it OnNavigationChanged
handle the event raise in your Form1
in the handled event method you can call wb.Navigate(url);
here a sample code
1- JobClass delegate
// define this delegate just above the JobClass
public delegate void JobClassNavigationEvent(string url);
2- define the event
public delegate void JobClassNavigationEvent(string url);
public static class JobClass
{
public static event JobClassNavigationEvent OnNavigationChanged;
private static BackgroundWorker worker;
public static void mainAsync()
{
worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
main();
};
worker.RunWorkerAsync();
}
private static void main()
{
gotoGoogle();
}
private static void gotoGoogle()
{
if (OnNavigationChanged != null)
OnNavigationChanged.Invoke("google.com");
}
private static void gotoYoutube()
{
if (OnNavigationChanged != null)
OnNavigationChanged.Invoke("youtube.com");
}
}
3- in your form
private void Form1_Load(object sender, EventArgs e){
JobClass.OnNavigationChanged+=(url)=>{
webBrowser1.Navigate(url);
// other code come here
};
JobClass.mainAsync();
}
hope this will help you
I have a console application in C#. If something goes wrong, I call Environment.Exit() to close my application. I need to disconnect from the server and close some files before the application ends.
In Java, I can implement a shutdown hook and register it via Runtime.getRuntime().addShutdownHook(). How can I achieve the same in C#?
You can attach an event handler to the current application domain's ProcessExit event:
using System;
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.ProcessExit += (s, e) => Console.WriteLine("Process exiting");
Environment.Exit(0);
}
}
Hook AppDomain events:
private static void Main(string[] args)
{
var domain = AppDomain.CurrentDomain;
domain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
domain.ProcessExit += new EventHandler(domain_ProcessExit);
domain.DomainUnload += new EventHandler(domain_DomainUnload);
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
Console.WriteLine("MyHandler caught: " + e.Message);
}
static void domain_ProcessExit(object sender, EventArgs e)
{
}
static void domain_DomainUnload(object sender, EventArgs e)
{
}
I'd recommend wrapping the call to Environment.Exit() in your own method and using that throughout. Something like this:
internal static void MyExit(int exitCode){
// disconnect from network streams
// ensure file connections are disposed
// etc.
Environment.Exit(exitCode);
}