471,337 Members | 802 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,337 software developers and data experts.

FileSystemWatcher communication to Windows FORM

Hi all,

I'm using a FileSystemWatcher to monitor a directory. I want the FSW
to pop up my already instantiated but invisible form.

However, I'm running into some problems with this.

1) In the FSW.Changed FileSystemEventhandler, I called the Show method
'frmMain.Show( )' on my form, the form appears but not completely
painted and it appears to be hanging with the hourglass.

private void OnCreated( )
{
frmMain.Show( );

//update the datasource, append to DataTable

}

2) Once I have my form fully painted and not hanging, I want the FSW
to continue communicating with the now visible form relaying
information about the incoming files. See, on the form I have a
DataGridView that has as its datasource a Datatable that is appended
to by the FSW in the OnChanged event above.

I have 2 main classes: FORM and MASTER. the FORM class is self
explanatory. The MASTER class inherits from the ApplicationContext
class. This is where the FSW is located. I do this to show the form
only when new files are detected by the FSW.
Anyone have any ideas or am able to shed some light on these
questions?

Any help is much appreciated.


public static void Main( )
{
Application.Run(new MASTER( ) );
}

public class MASTER : ApplicationContext
{
private System.IO.FileSystemWatcher;
...
}

public class FORM : Form
{
public System.Data.DataTable dt;
...
}

Jun 2 '07 #1
15 4558
On Sat, 02 Jun 2007 00:08:42 -0700, Angelo <an*******@gmail.comwrote:
[...]
1) In the FSW.Changed FileSystemEventhandler, I called the Show method
'frmMain.Show( )' on my form, the form appears but not completely
painted and it appears to be hanging with the hourglass.

[...]
2) Once I have my form fully painted and not hanging, I want the FSW
to continue communicating with the now visible form relaying
information about the incoming files. See, on the form I have a
DataGridView that has as its datasource a Datatable that is appended
to by the FSW in the OnChanged event above.

[...]
Anyone have any ideas or am able to shed some light on these
questions?
It seems to me that the main issue is that when the FileSystemWatcher
events are raised, the event handler is executed on a different thread
from your main UI thread. You should be able to address this problem by
using Form.Invoke() to execute the Show() method on the main UI thread
rather than calling Show() directly.

Likewise, I don't think there should be any problem having the event
handler update the DataGridView on the form, other than the fact that
there too you need to make sure you use Form.Invoke() to execute whatever
code will actually update the DataGridView.

Pete
Jun 2 '07 #2
hi,
if you want FSW to communicate with the directory.you have to open the
form in different thread.. you can use backgroundworker component for
this task or you can make some search about system.threading
namespace..
you must do multi-thread application and u make attention to the
access modifiers of the controls. for example you have to write
another form's control's text.this control's access modifier have to
be public..i hope this helps you.

Jun 2 '07 #3
On Sat, 02 Jun 2007 03:13:34 -0700, Hakan Fatih YILDIRIM
<hf*********@gmail.comwrote:
if you want FSW to communicate with the directory.you have to open the
form in different thread.. you can use backgroundworker component for
this task or you can make some search about system.threading
namespace..
I don't see how that will solve anything. The issue is that the FSW
raises the event on a thread different from that the form's message pump
is on. The FSW doesn't know which thread the form should be executing on,
and so it really doesn't matter which thread you put the form on, the FSW
isn't going to be able to raise the event on the form's thread.
you must do multi-thread application and u make attention to the
access modifiers of the controls.
I also don't see what access modifiers have to do with multi-threaded
code. It's my assertion that there's no need to create a new thread
anyway, but even if you did, access modifiers on the form's controls are a
completely separate issue.
for example you have to write
another form's control's text.this control's access modifier have to
be public..i hope this helps you.
It's true, if you have code outside a particular form that you want to
access that form's control directly, you have to change the access
modifier for that control so that it's public. But you have to do that
whether the code is executing on the same thread as the form or a
different one.

Furthermore, I would suggest that it is better to not expose a control on
a form in the general case, and rather to provide specific public methods
in the form to provide encapsulated access to the control. That way, only
the form itself has access to the control and doesn't have to worry about
some external code messing with the control in an undesirable way.

Pete
Jun 2 '07 #4
Hi,

You have to synchronize the event calling thread with the form's
thread (message pump thread). You can use the form's Invoke member
method to do so.

for instance:

....
void OnEvent()
{
if( frm.InvokeReuired )
frm.Invoke(new MethodInvoker(OnEvent));
else
frm.Text = "Event called...";
}
....

Hope this helps.
Moty

Jun 2 '07 #5
On Jun 2, 1:40 pm, Moty Michaely <Moty...@gmail.comwrote:
Hi,

You have to synchronize the event calling thread with the form's
thread (message pump thread). You can use the form's Invoke member
method to do so.

for instance:

...
void OnEvent()
{
if( frm.InvokeReuired )
frm.Invoke(new MethodInvoker(OnEvent));
else
frm.Text = "Event called...";}

...

Hope this helps.
Moty
Oops,

Just saw that Pete answered. Sorry.

Moty.

Jun 2 '07 #6
Guys,

Thanks for all your responses so far.

I've tried several things unsuccessfully.

1) Peter and Moty, I've tried form.Invoke( ) but I get an exception
that

"{"Invoke or BeginInvoke cannot be called on a control until the
window handle has been created."}"

The form has already been instantiated FORM frm = new FORM( ); and
in the constructor I call the ForceCreate( ) method.

Seems like a catch 22, with the form having to be already visible to
invoke the visible method.

Any ideas what's going on here?

2) I've also tried using a delegate to call the show method but still
I get the Exception above.

<CODE>
public delegate void delVoid( );

public class FORM
{
private System.IO.FileSystemWatcher FSW;

public FORM ( )
{
FSW = new FileSystemWatcher( ) ;

//FSW definition here
...
FSW.Created += new FileSystemEventHandler
( FSW_Created ) ;
FSW.EnableRaisingEvents = true;
}

private void FSW_Created( )
{
delVoid deleg = new delVoid( this.ShowForm ) ;
deleg.Invoke( ) ;
//have also tried deleg.BeginInvoke( null, null ) ;
}

private void ShowForm( )
{
this.Show( ) ;
}
}
</CODE>

On Jun 2, 2:08 am, Angelo <angelo...@gmail.comwrote:
Hi all,

I'm using a FileSystemWatcher to monitor a directory. I want the FSW
to pop up my already instantiated but invisible form.

However, I'm running into some problems with this.

1) In the FSW.Changed FileSystemEventhandler, I called the Show method
'frmMain.Show( )' on my form, the form appears but not completely
painted and it appears to be hanging with the hourglass.

private void OnCreated( )
{
frmMain.Show( );

//update the datasource, append to DataTable

}

2) Once I have my form fully painted and not hanging, I want the FSW
to continue communicating with the now visible form relaying
information about the incoming files. See, on the form I have a
DataGridView that has as its datasource a Datatable that is appended
to by the FSW in the OnChanged event above.

I have 2 main classes: FORM and MASTER. the FORM class is self
explanatory. The MASTER class inherits from the ApplicationContext
class. This is where the FSW is located. I do this to show the form
only when new files are detected by the FSW.

Anyone have any ideas or am able to shed some light on these
questions?

Any help is much appreciated.

public static void Main( )
{
Application.Run(new MASTER( ) );

}

public class MASTER : ApplicationContext
{
private System.IO.FileSystemWatcher;
...

}

public class FORM : Form
{
public System.Data.DataTable dt;
...

}- Hide quoted text -

- Show quoted text -

Jun 2 '07 #7
***** CORRECTION TO THE MY LAST POST *****

I used the frm.CreateControl( ) method, not frm.ForceCreate( ) that I
mentioned.

<CODE>

private void FSW_Created( )
{
this.Invoke( new MethodInvoker( this.ShowForm ) );
}

private void ShowForm( )
{
this.Show( ) ;
}

</CODE>
Jun 2 '07 #8
On Sat, 02 Jun 2007 10:12:12 -0700, Angelo <an*******@gmail.comwrote:
1) Peter and Moty, I've tried form.Invoke( ) but I get an exception
that

"{"Invoke or BeginInvoke cannot be called on a control until the
window handle has been created."}"

The form has already been instantiated FORM frm = new FORM( ); and
in the constructor I call the ForceCreate( ) method.

Seems like a catch 22, with the form having to be already visible to
invoke the visible method.

Any ideas what's going on here?
No. Well, yes, but I admit I don't really understand why the form's
underlying window handle hasn't been created yet. I can't find any
mention of a ForceCreate() method, so I can't comment on what you are
doing there. It does seem like there should be a way to force the form to
be created fully upon instantiation, but "should be" and "is" are
sometimes a long way apart. :)

You may find that you have to use Invoke() on the main form instead of the
status form. The main form would then optionally call Show() on the
status form, as well as displaying whatever data you want shown. I
suppose one might consider this a better design anyway, since it shifts
management of the status form to the main form where the management of
your UI should be anyway.

For example (warning: uncompiled, untested code...for illustration
purposes only :) ):

class MainForm
{
private StatusForm _status;
private FileSystemWatcher _fsw;

void InitFSW()
{
_fsw = new FileSystemWatcher();

_fsw.Created += FSW_CreatedInvoke;
}

void FSW_CreatedInvoke(object sender, FileSystemEventArgs fsea)
{
Invoke(new FileSystemEventHandler(FSW_Created), new object[]
{sender, fsea});
}

void FSW_Created(object sender, FileSystemEventArgs fsea)
{
if (_status == null)
{
_status = new StatusForm();
}

if (!_status.Visible)
{
_status.Show();
}

_status.FSW_Created(sender, fsea);
}
}

class StatusForm
{
void FSW_Created(object sender, FileSystemEventArgs fsea)
{
// do your actual status updating here
}
}
2) I've also tried using a delegate to call the show method but still
I get the Exception above.
No surprise there. A delegate is just a way to call a method. It's sort
of like a function pointer. It doesn't affect whether you are in a state
in which Invoke() is allowed or not.

Pete
Jun 2 '07 #9
On Sat, 02 Jun 2007 10:26:10 -0700, Angelo <an*******@gmail.comwrote:
***** CORRECTION TO THE MY LAST POST *****

I used the frm.CreateControl( ) method, not frm.ForceCreate( ) that I
mentioned.
Ah. That. Well, you'll note in the docs:

CreateControl does not create a control handle
if the control's Visible property is false

So, before calling CreateControl(), you need to make sure you set the
Visible property to true.

I think it's possible that is sufficient to solve your problem, rather
than all the extra code I posted. :)

Pete
Jun 2 '07 #10
Yes, Peter, you have to set the visible property to true before you
can call the frm.CreateControl( ) method.

However, setting the visible property to true (unless by the FSW)
would defeat the purpose of my current workflow. (setting
frm.Visible=true also hangs fhe form)

I have 2 classes, one for the form (FORM) and one for the FSW and
other miscellaneous members (MASTER). The 2nd class (MASTER) is only a
container class. It is a formless class (inherits from
ApplicationContext class) that is started by Application.Run( new
MASTER( ) ).

MASTER class has a structure and flow similar to the following:
- create an instance of the FORM class. -FORM frm = new FORM( );
- create the FSW and set to watch.
- upon new file creation, the FSW_Created handler is supposed to
then set the form to visible using frm.Show( ).
** This last portion is where the problem lies cause the form shows up
hanging. And if i simply use the frm.ShowDialog( ), the form shows
fine (not hanging) but then the entire process is halted (the FSW
stops monitoring because the process is halted by the now visible
Modal form). That is my problem.

I can't create a new form for each new file that enters. I simply want
the FSW to communicate to the already running form that new files have
arrived.

Hope that clears it up a bit.

Thanks for the help and insight so far. Any more suggestions are
welcome.

Angelo

Jun 2 '07 #11
On Sat, 02 Jun 2007 11:42:53 -0700, Angelo <an*******@gmail.comwrote:
[...]
MASTER class has a structure and flow similar to the following:
- create an instance of the FORM class. -FORM frm = new FORM( );
- create the FSW and set to watch.
- upon new file creation, the FSW_Created handler is supposed to
then set the form to visible using frm.Show( ).
Well, I don't have a great answer then. An ApplicationContext does not,
as far as I can tell, provide any mechanism for actually running code via
Invoke(). You can't get window messages without a window, and as far asI
know .NET doesn't support message-only windows (which is one way you'd do
it under the native Windows API...that allows you to get window messages
without having a visible window).

One possibility is to create a main window that you immediately hide
(Visible = false or, not as good, move it off-screen). Another
possibility is to not call Application.Run() until you actually have a
form around to process messages. Instead have the main thread create the
FSW, block on a waitable event that is set if and when the .NET event is
raised, and then create the "FORM" instance when the event is raised. The
main thread would then set a different waitable event to signal to the
thread handling the FSW event that it can now access the "FORM" instance
and call Invoke() on it. Finally the main thread would call
Application.Run() as before, once it's done with that initialization.

(You could probably do the inter-thread communication with the
Monitor.Wait() and Monitor.Pulse() methods, but since I'm less familiar
with that it's not the first thing that comes to mind :) ).

Personally, I question the basic design. One thing you don't explain is
how, without a way to process window messages, the user is supposed to
cause your application to exit. It seems like you ought to have *some*
kind of persistent user-interface if you're going to be a Windows
application. Where is that UI? If you had some sort of persistent place
where window messages were being processed, handling the FSW events would
be *much* simpler, even if you still wanted to only show the status form
("FORM") if and when the first event was raised.

As is usually the case, there's a basic user-interface design paradigm
that Windows applications all share, and when one tries to deviate from
that paradigm, all sorts of things we take for granted just get a lot
harder. At the same time, the user is usually inconvenienced, because the
application does not work in the way all the other ones they are used to
work. I won't go so far as to say there's no good reason to do things
like this, but I think one should consider it very carefully, especially
when one starts running into additional implementation problems caused by
the design deviation.

Pete
Jun 2 '07 #12
Thanks for the reply Pete.

In regard to your query.
Personally, I question the basic design. One thing you don't explain is
how, without a way to process window messages, the user is supposed to
cause your application to exit. It seems like you ought to have *some*
kind of persistent user-interface if you're going to be a Windows
application. Where is that UI? If you had some sort of persistent place
where window messages were being processed, handling the FSW events would
be *much* simpler, even if you still wanted to only show the status form
("FORM") if and when the first event was raised.

This solution was designed to run as a startup process and would
always run as long as the user is logged in. However, it would not be
very practical to always have the form visible. So the solution came
to resemble the functionality of a Windows Service. However, during
initial brainstorming, I figured there would be no reason for it be a
service as new files would only be created when the user is logged in.
So I kept with the design of a startup process. (That I would have a
watcher always running as long as the user is logged in and would
display the form upon detection of newly created files.)

This process is only supposed to monitor the FS and notify the user
(frm.Show( ) ) when new files come onto the FileSystem.

To answer your question though, to terminate the process, I would have
an event on the form that signals a flag on the main thread. The main
thread would then exit. (Application.ExitThread( ) )

As is usually the case, there's a basic user-interface design paradigm
that Windows applications all share, and when one tries to deviate from
that paradigm, all sorts of things we take for granted just get a lot
harder. At the same time, the user is usually inconvenienced, because the
application does not work in the way all the other ones they are used to
work. I won't go so far as to say there's no good reason to do things
like this, but I think one should consider it very carefully, especially
when one starts running into additional implementation problems caused by
the design deviation.

See explanation above.


Jun 2 '07 #13
On Sat, 02 Jun 2007 13:56:12 -0700, Angelo <an*******@gmail.comwrote:
To answer your question though, to terminate the process, I would have
an event on the form that signals a flag on the main thread. The main
thread would then exit. (Application.ExitThread( ) )
What form? The status form named "FORM"? What happens if no file system
changes ever occur? How does the user terminate the application in that
case?
Jun 2 '07 #14
On Jun 2, 6:15 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Sat, 02 Jun 2007 13:56:12 -0700, Angelo <angelo...@gmail.comwrote:
To answer your question though, to terminate the process, I would have
an event on the form that signals a flag on the main thread. The main
thread would then exit. (Application.ExitThread( ) )

What form? The status form named "FORM"? What happens if no file system
changes ever occur? How does the user terminate the application in that
case?
Pete,

If there isn't an event on the watched directory, the user will not
have a need to see the notification form. Remember, the only reason
the form pops up is to notify the user that a new file has been
created and to list certain details of that file and other processes.
The end user does not terminate this process. He/She can close the
form but the process continues to run in the background, listening for
more events on the watched directory and making the form visible when
another event is triggered by the FSW. The user terminating the
process is not part of the workflow. When the user logs off, the
process is terminated by Windows.

In the later stages of development I will build in an admin override
to terminate the process by use of a HotKey combination registered
with windows. But for now, the process is terminated by the logoff
process.

Jun 3 '07 #15
On Jun 3, 4:23 am, Angelo <angelo...@gmail.comwrote:
On Jun 2, 6:15 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Sat, 02 Jun 2007 13:56:12 -0700, Angelo <angelo...@gmail.comwrote:
To answer your question though, to terminate the process, I would have
an event on the form that signals a flag on the main thread. The main
thread would then exit. (Application.ExitThread( ) )
What form? The status form named "FORM"? What happens if no file system
changes ever occur? How does the user terminate the application in that
case?

Pete,

If there isn't an event on the watched directory, the user will not
have a need to see the notification form. Remember, the only reason
the form pops up is to notify the user that a new file has been
created and to list certain details of that file and other processes.
The end user does not terminate this process. He/She can close the
form but the process continues to run in the background, listening for
more events on the watched directory and making the form visible when
another event is triggered by the FSW. The user terminating the
process is not part of the workflow. When the user logs off, the
process is terminated by Windows.

In the later stages of development I will build in an admin override
to terminate the process by use of a HotKey combination registered
with windows. But for now, the process is terminated by the logoff
process.
I tried to post an idea but i see it didn't pass :( so I'll post it
again:

It's better to use SynchronizationContext. I would use it this way:

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(fals e);
Application.Run(new Form1());
}

public partial class Form1 : Form
{
private SynchronizedClass sync;

public Form1()
{
InitializeComponent();
}

void sync_Created(object sender, EventArgs e)
{
Form1 frm = new Form1();
frm.Text = "Bla";
frm.Show();
}

private void button2_Click(object sender, EventArgs e)
{
sync = new SynchronizedClass();
sync.Created += new EventHandler(sync_Created);
}
}
// This class will be used as a wrapper to the FSW class. The events
will be raised according to the FSW events.
public class SynchronizedClass
{
private SynchronizationContext context;

public event EventHandler Created;

public SynchronizedClass()
{
// It's important to get the current
SynchronizationContext
// object here in the constructor. We want the
// SynchronizationContext object belonging to the thread
in
// which this object is being created.
context = SynchronizationContext.Current;

if (context == null)
context = new SynchronizationContext();

ThreadPool.QueueUserWorkItem(
delegate(object state)
{
// would be true
context.Send(new SendOrPostCallback(
delegate(object someState)
{
if (Created != null)
{
Created(this, EventArgs.Empty);
}
}), null);
}
);
}
}
Hope this helps.
Moty.

Jun 3 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Craig Thompson | last post: by
2 posts views Thread by Sacha Korell | last post: by
21 posts views Thread by dast | last post: by
1 post views Thread by Frederic H | last post: by
4 posts views Thread by hooksie2 | last post: by
17 posts views Thread by Mufasa | last post: by
1 post views Thread by Lila Godel | last post: by
reply views Thread by rosydwin | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.