I'm new in developing in Visual Studio so I hope my problem is not too stupid :-)
I try to establish a FileWatcher in my VSPackage to detect any changes performed in the current solution.
For this I found the class FileWatcher, which - in my opinion - detect any file changes.
But anything in my code must be wrong as no event is fired.
Maybe you can help me?
The solution I want to watch is in D:\\Test but entering the specific path doesn't help
class Watcher
{
FileSystemWatcher watcher = new FileSystemWatcher();
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void StartWatching()
{
Debug.WriteLine("in watcher method");
watcher.Path = #"D:\\";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
watcher.EnableRaisingEvents = true;
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
Debug.WriteLine("Changes in folder:" + e.FullPath);
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
Debug.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
private static void OnDeleted(object source, RenamedEventArgs e)
{
Debug.WriteLine("deleted");
}
private static void OnCreated(object source, RenamedEventArgs e)
{
Debug.WriteLine("created");
}
}
In the initialize method of my VSPackage i call:
("in watcher method" is displayed in output so this part should work)
watch = new Watcher();
watch.StartWatching();
Tank you in advance!
EDIT
I found out, that the path at the test environment changes.
But now I have the problem, that I'm not able to get the name of the changed file, as the change event only gives me .opensdf or .sdf
Can you help me?
Instead of watching the file changes yourself you can use the built in events provided by Visual Studio: SolutionEvents and ProjectItemEvents. This Stack Overflow post explains how to use them in a vs package.
Related
I have this c++ code that is supposed to detect when a file has been modified in a directory and add the file name to a list box.
This is the file watcher part which is inside a button that starts the monitoring process
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
array<String^>^ args = Environment::GetCommandLineArgs();
FileSystemWatcher^ fsWatcher = gcnew FileSystemWatcher( );
fsWatcher->Path = "C:\\users\\patchvista2";
fsWatcher->IncludeSubdirectories = true;
fsWatcher->NotifyFilter = static_cast<NotifyFilters>
(NotifyFilters::FileName |
NotifyFilters::Attributes |
NotifyFilters::LastAccess |
NotifyFilters::LastWrite |
NotifyFilters::Security |
NotifyFilters::Size );
Form1^ handler = gcnew Form1();
fsWatcher->Changed += gcnew FileSystemEventHandler(handler, &Form1::OnChanged);
fsWatcher->Created += gcnew FileSystemEventHandler(handler, &Form1::OnChanged);
fsWatcher->EnableRaisingEvents = true;
}
then for the onchange part I have this code
void OnChanged (Object^ source, FileSystemEventArgs^ e)
{
// Here is the problem
MessageBox::Show(e->FullPath);
listBox1->Items->Add(e->FullPath);
// End problem
System::Security::Cryptography::MD5 ^ md5offile = MD5CryptoServiceProvider::Create();
array<Byte>^ hashValue;
FileStream^ fs = File::Open(e->FullPath, IO::FileMode::Open, IO::FileAccess::Read, IO::FileShare::ReadWrite);
fs->Position = 0;
hashValue = md5offile->ComputeHash(fs);
PrintByteArray(hashValue);
fs->Close();
Application::DoEvents();
}
It will message box me the file name but it will not add it to the list box. I tried having it display the file name to a label but that did not work either. it seems like the screen is not refreshing once this code loop is started. I have this code in vb.net and it does add the file name to the list box. can someone show me why the file name is not getting added tot the list box.
Two things:
You need to keep the FileSystemWatcher alive. It's liable to be garbage collected where you've got it now. (Create a class field and stick it there.)
You need to Invoke onto the UI thread whenever you do anything with a UI component.
Here's the approximate syntax for #2 (I'm away from a compiler at the moment, this may not be exact.)
void Form1::AddToListBox(String^ filename)
{
listBox1->Items->Add(filename);
}
void Form1::OnChanged(Object^ source, FileSystemEventArgs^ e)
{
Action<String^>^ addDelegate = gcnew Action<String^>(this, &Form1::AddToListBox);
this->Invoke(addDelegate, e->FullPath);
...
}
So I've downloaded the samples from http://archive.msdn.microsoft.com/ManagedMediaHelpers.
I've got my code working using MP3MediaStreamSource. However, I don't fully understand the code would like some explanation.
public partial class MainPage : PhoneApplicationPage
{
private static string mediaFileLocation = "http://file-here.mp3";
private static HttpWebRequest request = null;
private static Mp3MediaStreamSource mss = null;
public MainPage()
{
InitializeComponent();
}
private void RequestCallback(IAsyncResult asyncResult)
{
HttpWebResponse response = request.EndGetResponse(asyncResult) as HttpWebResponse;
Stream s = response.GetResponseStream();
mss = new Mp3MediaStreamSource(s, response.ContentLength);
Deployment.Current.Dispatcher.BeginInvoke(
() =>
{
this.wp7AudioElement.Volume = 100;
this.wp7AudioElement.SetSource(mss);
});
}
private void Button_Click(object sender, RoutedEventArgs e)
{
request = WebRequest.CreateHttp(MainPage.mediaFileLocation);
// NOTICE
// Makes this demo code easier but I wouldn't do this on a live phone as it will cause the whole
// file to download into memory at once.
//
// Instead, use the asynchronous methods and read the stream in the backgound and dispatch its
// data as needed to the ReportGetSampleCompleted call on the UIThread.
request.AllowReadStreamBuffering = true;
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(this.RequestCallback), null);
}
}
It's really just the last method I need explained, I don't understand the Notice as to why it's a bad idea and how to do it differently?
Basically, it is trying to tell you that you are downloading 1 file COMPLETELY before it plays. It is not a good idea, since if the file is 10 MB, it may take a while before it completely downloads.
A better idea would be to chunk the file using Encoders, and read it in on need basis.
I have an action I need to perform around 3 seconds after my app starts. I've implemented it as follows:
internal static class Entry
{
private static SplashScreen splashScreen;
[STAThread]
internal static void Main()
{
ShowSplashScreen();
StartApp();
}
private static void ShowSplashScreen()
{
splashScreen = new SplashScreen("Splash.png");
splashScreen.Show(false, true);
}
private static void StartApp()
{
var app = new App();
//this, in particular, is ugly and more difficult to comprehend than I'd like
var dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
dispatcherTimer.Tick += delegate
{
CloseSplashScreen();
dispatcherTimer.Stop();
};
dispatcherTimer.Start();
app.Run();
}
private static void CloseSplashScreen()
{
splashScreen.Close(TimeSpan.FromSeconds(1));
}
}
I find the StartApp() code rather ugly but have not been able to concoct a neater alternative. Is there a common idiom I'm missing here?
PS. Yes, I'm aware SplashScreen has an auto-close option. I'm not wanting to use that mainly because it begins closing as soon as the app has loaded, which I don't want to do.
Here is something similar you might be interested in:
How do we do idle time processing in WPF application?
It's not exactly what you are looking for, because it will close your window as soon as your app goes idle, but you might consider to start your delay after your app went idle. You might find that link helpful than.
Do you not have a specific state when your application is done starting? Normally you want your SplashScreen to close when your application is ready to handle user input, instead of an arbitrary 3 secs. So I would suggest to close your SplashScreen then.
This is about the best I could come up with:
internal static class Entry
{
private static SplashScreen splashScreen;
private static App app;
[STAThread]
internal static void Main()
{
ShowSplashScreen();
CreateApp();
PumpDispatcherUntilPriority(DispatcherPriority.Loaded);
PumpDispatcherFor(TimeSpan.FromSeconds(2));
CloseSplashScreen();
PumpDispatcherUntilAppExit();
}
private static void ShowSplashScreen()
{
splashScreen = new SplashScreen("Splash.png");
splashScreen.Show(false, true);
}
private static void CloseSplashScreen()
{
splashScreen.Close(TimeSpan.FromSeconds(0.5));
}
private static void CreateApp()
{
app = new App();
}
private static void PumpDispatcherUntilPriority(DispatcherPriority dispatcherPriority)
{
var dispatcherFrame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke((ThreadStart)(() => dispatcherFrame.Continue = false), dispatcherPriority);
Dispatcher.PushFrame(dispatcherFrame);
}
private static void PumpDispatcherFor(TimeSpan timeSpan)
{
var dispatcherFrame = new DispatcherFrame();
using (var timer = new Timer(o => dispatcherFrame.Continue = false, null, (long)timeSpan.TotalMilliseconds, Timeout.Infinite))
{
Dispatcher.PushFrame(dispatcherFrame);
}
}
private static void PumpDispatcherUntilAppExit()
{
var dispatcherFrame = new DispatcherFrame();
app.Exit += delegate
{
dispatcherFrame.Continue = false;
};
Dispatcher.PushFrame(dispatcherFrame);
}
}
I toyed with extension methods for Dispatcher, but ultimately found them less intuitive. That's because PushFrame() is static, so any extension methods don't actually execute against the Dispatcher they're invoked against. YMMV.
Note that you could also call app.Run() instead of PumpDispatcherUntilAppExit(), but I just did that for consistency.
Does not really matter if it is ugly, you can just refactor it into a method which takes an Action as parameter for example and that won't be much of a problem.
As by ugly you probably meant that it looks like bad code i would suggest the use of a normal thread (with Thread.Sleep before your action) which uses Dispatcher.Invoke instead. I for one am not aware of any best practice regarding this though. This can also be nicely refactored into a simple method taking an Action.
If you want a non-blocking wait there is a question to be found about that as well.
I've made a rather complex Silverlight 4 out-of-browser application. One of my main view models adds an event handler to the Application.Current.MainWindow.Closing event.
This works fine when the application is initially run. It is able to cancel the close operation.
However, sometimes after performing operations like showing and closing a ChildWindow, the MainWindow's Closing event is no longer calling my handler.
In the debugger, I added a watch to the MainWindow's underlying closing event delegate. It's not null before showing the ChildWindow. Then sometimes after the ChildWindow is closed the delegate is null. This is explains why my handler is not called any more. But why is this delegate getting nulled? And why is it only happening occasionally?
My application is not unbinding my event handler at any point.
This is the delegate I'm watching:
System.Windows.Application.Current.MainWindow.m_closingEvent
Other stuff: I'm using Caliburn Micro
I had the exact same problem. We have a large silverlight application running OOB.
For some reason the m_ClosingEvent was nulled after running for a while. I have not been able to find the cause of this issue but I think it may have something to do with us changing the root visual or all the child windows we show.
I´m using a class ApplicationWrapper.
public class ApplicationWrapper : IApplicationWrapper
{
public void Initialize()
{
HookCloseEvent(true);
}
private void HookCloseEvent(bool hook)
{
if (hook && IsRunningOutOfBrowser)
{
Application.Current.MainWindow.Closing += OnClosing;
}
else
{
if (IsRunningOutOfBrowser)
{
Application.Current.MainWindow.Closing -= OnClosing;
}
}
}
private void OnClosing(object sender, ClosingEventArgs e)
{
InvokeClosing(e);
}
... etc..
}
And the InvokeClosing method was never called. But when I changed it to
public class ApplicationWrapper : IApplicationWrapper
{
private Window _mainWindow;
public void Initialize()
{
if(IsRunningOutOfBrowser)
{
_mainWindow = Application.Current.MainWindow;
}
HookCloseEvent(true);
}
private void HookCloseEvent(bool hook)
{
if (hook && IsRunningOutOfBrowser)
{
_mainWindow.Closing += OnClosing;
}
else
{
if (IsRunningOutOfBrowser)
{
_mainWindow.Closing -= OnClosing;
}
}
}
private void OnClosing(object sender, ClosingEventArgs e)
{
InvokeClosing(e);
}
... etc...
}
The m_ClosingEvent isn´t nulled.
So, try to just store the "initial" MainWindow in a field and check if that solves your problem.
Instead of hooking to the event, why not register a service instead? Create a class that implements IApplicationService and IApplicationLifetimeAware. The latter gives you an "onexiting" and "onexited" pair of events. You place the service in the application by pointing to it in a section called in your App.xaml. I've used this for many projects and never had an issue with the exiting methods not being called.
Ok, after pulling out my hair and many false starts I finally found the answer - it seems to be a known bug with the Closing event, OOB and ChildWindows open/closes...
The trick is to store a static reference to the Main Window:
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
//you have to store this to work around the bug
//http://forums.silverlight.net/forums/p/185664/424174.aspx
_mainWindow = App.GetApp.MainWindow;
App.GetApp.MainWindow.Closing += (s, e1) =>
{
if (UIUtilities.ShowMessage("Would you like to exit AMT Mobile?", "Exit Application", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
{
e1.Cancel = true;
}
};
}
Currently, I have something like:
public partial class Form1 : Form
{
delegate void StringDelegate(string value);
private FTP m_ftp;
public Form1()
{
InitializeComponent();
}
private void connect_Click(object sender, EventArgs e)
{
OnResponse("Connecting");
m_ftp = new FTP(server.Text);
m_ftp.ResponseReceived += new FTPResponseHandler(m_ftp_ResponseReceived);
m_ftp.Connected += new FTPConnectedHandler(m_ftp_Connected);
m_ftp.BeginConnect(user.Text, password.Text);
}
void m_ftp_Connected(FTP source)
{
// when this happens we're ready to send command
OnResponse("Connected.");
}
void m_ftp_ResponseReceived(FTP source, FTPResponse Response)
{
OnResponse(Response.Text);
}
private void OnResponse(string response)
{
if (this.InvokeRequired)
{
this.Invoke(new StringDelegate(OnResponse), new object[] { response } );
return;
}
}
private void getFileList_Click(object sender, EventArgs e)
{
FTPFiles files = m_ftp.EnumFiles();
fileList.Items.Clear();
foreach (FTPFile file in files)
{
fileList.Items.Add( new ListViewItem( new string[] { file.Name, file.Size.ToString() } ));
}
tabs.SelectedIndex = 1;
}
private void upload_Click(object sender, EventArgs e)
{
FileStream stream = File.OpenRead("\\My Documents\\My Pictures\\Waterfall.jpg");
m_ftp.SendFile(stream, "waterfall.jpg");
stream.Close();
}
Which works fine - this example was taken from the samples. However, after a recent re-visit I have a question. In this particular case since OnResponse() function doesn't update the UI, it seems to serve no purpose here. I removed it (as well as all the calls to it) and it still works like before. Am I missing something?
After reading up more about multi threading with forms, I came to understand that this mechanism (demonstrated in the code above) is there to make sure the UI is responsive.
So in case when we need to say, update a UI element (such as textbox, label etc) we would have OnResponse implemented as follows:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(!InvokeRequired)
{
button1.Text = dummy;
}
else
Invoke(new StringDelegate(OnResponse),new object[] {enabled});
}
If this function is implemented as:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(InvokeRequired)
{
Invoke(new StringDelegate(OnResponse),new object[] {dummy});
return;
}
}
What's the use to have it at all? Is it absolutely necessary?
And another question: is ftp object running on its own thread here?
The FTP object is definitely running on its own thread. How do I know? This line:
m_ftp.BeginConnect(user.Text, password.Text);
This is an asynchronous method. Once you call this, the FTP component will use a thread from the .NET threadpool to do all of the work. This dedicated thread is the one that is used to "raise" the events. Ultimately a "raised event" is just one or more method calls to all of the delegates added to the event invocation list; it is this dedicated thread spun up by the Begin method that calls these methods. This thread is not the same thread as the thread that runs the UI, hence the need for the Invoke calls.
If you want the FTP component to use the UI thread, you'd use the Connect method instead of the BeginConnect method. This means your events wont work either, nor will your UI respond to interaction - this is completely expected because a thread can only do one thing at a time: it's either servicing the UI, or executing the FTP code. This is why you need a 2nd thread.
Make sense?
-Oisin