I have a Winform program I wrote for a university so they could run test files.
The program is targeted at .NET 4.5 and was developed and run on Windows 7.
To make the running of files easy for the technicians I added the ability to save the paths to the test files. The file path is stored in a settings file (ProgSettings.settings) under the variable "RunNames".
When the save button is pressed I run a validation to ensure the test file at the end of the path exists and is valid before adding it to the RunNames list:
/*
*Function: SaveButton_Click(sender, e)
*Notes: responds to the button click "Save"
* tries to save file (if valid) to settings
*/
private void SaveButton_Click(object sender, EventArgs e)
{
if (ValidateFile(TrackFileName.Text))
{
string displayName = updateLinkNames(TrackFileName.Text).ToUpper();
if (!ListOfTracks.Items.Contains(displayName))
{
ListOfTracks.Items.Add(displayName);
runNames.Add(TrackFileName.Text);
}
updateSettings();
}
}
/*
*Function: ValidateFile(fileName)
*Notes: called from save button click
* checks validity of the file path
*/
private bool ValidateFile(string fileName)
{
fileName = fileName.ToUpper();
FileToRun.FileName = fileName;
validFile = System.IO.File.Exists(fileName);
if(fileName != null && fileName != "" && fileName.EndsWith(".TXT") && validFile)
{
return true;
}
else
{
return false;
}
}
/*
*Function: updateSettings()
*Notes: updates the settings with the valid path
*/
private void updateSettings()
{
string value = String.Join(",", runNames.Select(i => i.ToString()).ToArray());
ProgSettings.Default.RunNames = value;
ProgSettings.Default.Save();
}
(For those of you unfamiliar with .settings they store the basic types available on C#, there are ways to include arrays as well but the simplest solution is to concatenate the different parts of the array in a string with a separator - in my case ",").
Then when I load the program again I populate a list of checkboxes using the a getSavedFiles() function below.
private List<string> getSavedFiles()
{
string localRunNames = ProgSettings.Default.RunNames.ToUpper();
string[] arr = localRunNames.Split(',').Select(s => Convert.ToString(s)).ToArray();
return arr.Cast<String>().ToList();
}
The settings works correctly on both my work computer and my personal laptop I did testing on. However, now the program is in use at the university they are saying that after shutting down the computer the next time the run the program all the saved file paths are gone.
Is this due to how to how the university managers users accounts on the computer? Or is there some other reason for this?
Was there another alternative to storing setting information for cases where .settings files don't work? (The only other solution I can think of is having the program write a config.txt file which I would prefer not to do encase the application is used somewhere it won't having writing permissions)
Below is a link to a question about the best practice to save application settings:
Best practice to save application settings
Related
C# Windows Forms.
I have successfully used Application Settings to save and load user settings for the values of controls on my form.
I have a checkbox and code where I can set whether this happens automatically (at application start and close), or not.
I also have a menu so I can load them and save them during runtime.
This is all using the default user.config.
Example.
In Application settings I have (for one of the items, which is a radio button called RbBitRate6Mbps):
Name: BitRate6Mbps
Type: String
Scope: User
Value: False
To save the settings I have a menu item, Save Defaults. This runs:
if (RbBitRate6Mbps.Checked == true)
{
Settings.Default["BitRate6Mbps"] = "True";
}
else
{
Settings.Default["BitRate6Mbps"] = "False";
}
Settings.Default.Save();
To load the settings back in I have a menu item, Load Defaults. This runs:
if (Settings.Default["BitRate6Mbps"].ToString() == "True")
{
RbBitRate6Mbps.Checked = true;
}
else
{
RbBitRate6Mbps.Checked = false;
}
There are about 10 other controls I save and load (text boxes, check boxes and radio buttons), in the rest of the above code.
This is all working with no issues.
Now I would like to have several sets of these settings, each will contain some identical values and some different ones.
Each will have a different file name and be saved into a custom location (which will be the app folder, by default).
I do not mind what format the file is (xml, ini, etc), but if it is the same as the default, this would be good.
I have created new menu items, Save Custom Settings and Load Custom Settings.
I have added a SaveFileDialog and a LoadFileDialog to hopefully be used for the above.
But if these are not necessay, that is good too.
This is where I have become stuck.
I have been searching for days for a clear example of how to do this.
I have been unable to find much. What I have found, I have been unable to understand the documentation.
I am thinking loading the settings back in will be the easier part?
But I also think, for saving the file, using:
Settings.Default.Save();
Will not accomplish my aims as it will just write to the default user.config file ?
Is what I want to do possible?
If so does anyone have any instructions and example code?
Update. I have installed a new Settings Provider and it is working well. It saves the XML to the app folder. I have also set up INI files to save the settings. Using both a custom path and custom file name. It allows for multiple INI files to be created. This also works extremely well.
Edit: Updated code (and instructions) so it is no longer necessary to create any custom folder manually. If it does not exist, it will be created.
The XML Settings Provider developers project is located here:
Settings Providers on Github
The INI file developers project (and demo) is located here:
C# WinForms Ini File demo on Github
Below are the instructions for setting up the new Settings Provider with an XML file and following that are the instructions for saving the settings to INI files (both types can be used in the same project at the same time, as I am doing here):
Using a new Settings Provider to save settings in an XML file:
1.
Setup the Application Settings (in Solution Explorer, right-click on the App. Then Select: Properties. Then open: Settings).
Name: txtFullName
Type: String
Scope: User
Value: John Doe
Name: txtSchool
Type: String
Scope: User
Value: Oxford
Name: txtClass
Type: String
Scope: User
Value: 4B
Name: chkActiveStudent
Type: bool
Scope: User
Value: True
2.
Install, from NuGet the new Settings Provider (in Solution Explorer, right-click on: References. Then Select: Manage NuGet Packages. Then search for: PortableSettingsProvider. Install it).
3.
In Program.cs modify static void Main(). Add to it the lines below.
//PortableSettingsProvider.SettingsFileName = "portable.config";
//PortableSettingsProvider.SettingsDirectory = "c:\\\testconfig\\\school";
//System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
If accepting the default settings (the config file, portable.config, will be created in the applications folder), a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//PortableSettingsProvider.SettingsFileName = "portable.config";
//PortableSettingsProvider.SettingsDirectory = "c:\\testconfig\\school";
//System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
3a.
To choose a different filename and location, remove the comments (//) and change to your preference for filename and location (double slashes are needed between the folder names). In this example I use settings.config as the filename and c:\testconfig\school as the path). In this case a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
PortableSettingsProvider.SettingsFileName = "settings.config";
PortableSettingsProvider.SettingsDirectory = "c:\\testconfig\\school";
System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
3b.
If you would like the settings directory to be created in a subfolder of the applications working directory, then change the code to include the subfolder name (in this example I use settings.config as the filename and Settings as the subfolder). In this case a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
PortableSettingsProvider.SettingsFileName = "settings.config";
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
PortableSettingsProvider.SettingsDirectory = strSettingsDirectory;
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
4.
Still in Program.cs, add the following line to the bottom of the existing using section.
using Bluegrams.Application;
5.
On the form create some controls (these will correspond to the Application Settings made in step 1).
TextBox. Name: txtFullName
TextBox. Name: txtSchool
Textbox. Name: txtClass
Checkbox. Name: chkActiveStudent
Button. Name: btnLoadSettings Text: Load Config
Button. Name: btnSaveSettings Text: Save Config
6.
Enter the code for the Load Config buttons click events (btnLoadSettings).
private void btnLoadSettings_Click(object sender, EventArgs e)
{
txtName.Text = Properties.Settings.Default.txtName.ToString();
txtSchool.Text = Properties.Settings.Default.txtSchool.ToString();
txtClass.Text = Properties.Settings.Default.txtClass.ToString();
if (Properties.Settings.Default.chkActiveStudent == true)
{
chkActiveStudent.Checked = true;
}
else
{
chkActiveStudent.Checked = false;
}
}
7.
Enter the code for the Save Config buttons click events (btnSaveSettings).
private void btnSaveSettings_Click(object sender, EventArgs e)
{
Properties.Settings.Default.txtName = txtName.Text;
Properties.Settings.Default.txtSchool = txtSchool.Text;
Properties.Settings.Default.txtClass = txtClass.Text;
if (chkActiveStudent.Checked == true)
{
Properties.Settings.Default.chkActiveStudent = true;
}
else
{
Properties.Settings.Default.chkActiveStudent = false;
}
Properties.Settings.Default.Save();
}
8.
That’s it.
Run the app.
Load the settings using the first button).
Make some changes to the text on the controls.
Save them using the second button.
If you have not created a custom filename and/or path then in your app folder there should be a new file: portable.config.
Mine is located at: C:\Users\flakie\source\repos\TestApp\TestApp\bin\Debug
You can open the file in an txt/xml editor to verify the values were set.
If you run the app again, and load settings, you should see the new values.
The Code for Saving Settings to Multiple INI Files
The following instructions are easier to implement.
They do not require you to set-up the Application Settings as they are not used.
The settings will be saved in 1 or more INI files.
The path can be changed on-the-fly (though a default is set), as can the file name for the INI file.
Again it will be using the applications own folder as the default destination (for the INI files).
You will need to modify the Form.cs file only.
The demo (from the link above) is easy to understand and was enough to provide me with the knowledge to create this example (and I am a C# novice).
9.
Install, from NuGet, the INI files package (in Solution Explorer, right-click on: References. Then Select: Manage NuGet Packages. Then search for: PeanutButter.INI. Install it).
10.
In your Form.cs file (Form1.cs if you have not changed the name), add the following line to the bottom of the existing using section.
using PeanutButter.INIFile;
11.
In your Form.cs file, directly under the line, public partial class Form1 : Form, add the following single line of code.
private IINIFile _loadedConfig;
It should look like the below.
public partial class Form1 : Form {
private IINIFile _loadedConfig;
12.
On the form create two more buttons.
Button. Name: btnOpenIniFile Text: Open INI
Button. Name: btnSaveIniFile Text: Save INI
13.
Enter the code for the Open INI buttons click event (btnOpenIniFile).
private void btnOpenIniFile_Click(object sender, EventArgs e) {
using(OpenFileDialog OpenFileIni = new OpenFileDialog()) {
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
OpenFileIni.InitialDirectory = strSettingsDirectory;
OpenFileIni.Filter = "INI File|*.ini";
OpenFileIni.RestoreDirectory = true;
OpenFileIni.CheckFileExists = true;
OpenFileIni.CheckPathExists = true;
OpenFileIni.Title = "Open an INI Settings File";
if (OpenFileIni.ShowDialog() == DialogResult.OK)
{
_loadedConfig = new INIFile(OpenFileIni.FileName);
txtName.Text = _loadedConfig.HasSetting("UserSettings", "txtName") ? _loadedConfig["UserSettings"]["txtName"] : "";
txtSchool.Text = _loadedConfig.HasSetting("UserSettings", "txtSchool") ? _loadedConfig["UserSettings"]["txtSchool"] : "";
txtClass.Text = _loadedConfig.HasSetting("UserSettings", "txtClass") ? _loadedConfig["UserSettings"]["txtClass"] : "";
if (_loadedConfig["UserSettings"]["chkActiveStudent"] == "Checked")
{
chkActiveStudent.Checked = true;
}
else
{
chkActiveStudent.Checked = false;
}
}
}
}
14.
Enter the code for the Save INI buttons click event (btnSaveIniFile).
private void btnSaveIniFile_Click(object sender, EventArgs e)
{
using (SaveFileDialog SaveFileIni = new SaveFileDialog())
{
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
SaveFileIni.InitialDirectory = strSettingsDirectory;
SaveFileIni.Filter = "INI File|*.ini";
SaveFileIni.Title = "Save an INI Settings File";
if (SaveFileIni.ShowDialog() == DialogResult.OK)
{
_loadedConfig = new INIFile(SaveFileIni.FileName);
_loadedConfig["UserSettings"]["txtName"] = txtName.Text;
_loadedConfig["UserSettings"]["txtSchool"] = txtSchool.Text;
_loadedConfig["UserSettings"]["txtClass"] = txtClass.Text;
if (chkActiveStudent.Checked == true)
{
_loadedConfig["UserSettings"]["chkActiveStudent"] = "Checked";
}
else
{
_loadedConfig["UserSettings"]["chkActiveStudent"] = "UnChecked";
}
_loadedConfig.Persist();
}
}
}
15.
That’s it. Run the app.
Make some changes to the text on the textbox controls. Save them using the Save INI button.
You will be prompted for a file name. It can be anything you like (but in this example I used the name of the person I setup in the first textbox.
You do not need to enter the ini file extension. You can change the location if you wish.
Make some more changes to the text in the textBoxes but do not save them.
Click on the Open INI button. Browse to the ini file you just saved and open it.
The text you just modified, without saving, should now be changed to the text you saved into the ini file.
Use OpenExeConfiguration function to read settings and then Add/Update key values before Save it back. Finally you can ConfigurationManager.RefreshSection to refresh settings of a particular section.
Example at Link
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager
.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}
A common thing I do is name files by the current date/time. For instance, I'll name something 12-31-2016-08-46-01.jpg
This is great. It works well. But typing it every time is annoying, so I thought it useful to just write a small program that returns the output as a string. That was easy enough.
public class Program {
public static string Main() {
var strFilename = new DateTimeFilename();
return strFilename.Current();
}
public class DateTimeFilename {
public string Current () {
return // ... logic ... //
}
}
And then I add this program as a context menu option in the Windows registry.
Except that doesn't work. Apparently, I cannot return a string from the actual program.
So is there a way to get the string out of the program and into whatever my cursor is trying to type into at the time?
I would recommend that you work within Windows File Explorer and add a Send To option which does this operation and passes the current selected file name to the clipboard.
The following takes the selected filename and adds a custom date after the name, but before the extension, such as TheFile.20211123.txt:
static void Main(string[] args)
{
var name = $"{Path.GetFileNameWithoutExtension(args[0])}.{DateTime.Now.ToString("yyyyMMdd")}{Path.GetExtension(args[0])}";
// MessageBox.Show(name);
Clipboard.SetText(name);
}
Build the program and the create a file explorer short cut to the exe built. Then place the shortcut to this folder:
C:\Users\{username}\AppData\Roaming\Microsoft\Windows\SendTo
Then in File Explorer right click, select Send To and select the shortcut name you gave it.
Then paste the new name where ever you need it, for it resides in your clipboard.
I'm creating a media player.
So far I can open a file type with my C# application by double clicking on the file. But I want to open multiple files by selecting them and opening them at once..
My code goes as follows:
App.xmal.cs
protected override void OnStartup(StartupEventArgs e)
{
if (e.Args != null && e.Args.Length > 0)
{
this.Properties["ArbitraryArgName"] = e.Args[0];
}
base.OnStartup(e);
}
MainWindow.xmal.cs
if (Application.Current.Properties["ArbitraryArgName"] != null)
{
string fname = Application.Current.Properties["ArbitraryArgName"].ToString();
if (fname.EndsWith(".mp3") || fname.EndsWith(".wma") || fname.EndsWith(".wav") || fname.EndsWith(".mpg") ||
fname.EndsWith(".mpeg") || fname.EndsWith(".mp4") || fname.EndsWith(".wmv") )
{
doubleclicktrack(fname);
}
else
{
this.Close();
}
}
This code works fine with one file, but how to change this in order to open multiple files at once by selecting multiple files and opening them at once (by pressing enter key).
You will have to look into developing shell extensions in order to achieve what you want. Just by using the registry to associate file types with your app, you are limited to passing just one file per command, which will end up opening your app once per file (which you have confirmed).
I guess you could also implement your app to allow only one instance running globally. That way, whenever a command comes in to open one more file, you could for example add it to a playlist or something.
Note that shell extensions have to be written in C++, Microsoft strongly advises to avoid managed code for this purpose.
You can find the documentation starting point here: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776778(v=vs.85).aspx
FileOpenPicker can do that (Code for UWP or Windows 8.1 desktop, with Windows 8.1 phone it's a bit trickier):
private static readonly string[] FileTypes = {
"aac", "adt", "adts", "mp3", "m3a", "m4a", "mpr", "3gp", "3g2",
"flac", "wav", "wma" };
...........
FileOpenPicker picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
foreach (String fileType in FileTypes)
picker.FileTypeFilter.Add("." + fileType);
var list = await picker.PickMultipleFilesAsync();
FYI Your manifest must declare "Music Library" in Capabilities
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm looking to move my C# application .EXE when ran to lets say... Documents and then delete from the place which it was executed.
For example, If I ran my .EXE on my desktop before running the program copy itself to the directory "documents" and then delete the one from executed directory (which in my case is desktop) after running the new one in documents.
Process: Run > Move to C://Documents > Start .EXE in documents > Delete the .EXE from the executed directory.
Sorry if this may come across hard to understand for some people I tried my best to specifically state what I wanted to accomplish.
I hope you can write the program in this way which will help.
1) program
i) Check if the program's execution directory is not C:/Documents
then it should copy the folder and put it in C:/Documents
and start the exe inside the documents
ii) else get a running list of the exe and their execution directory
(if its not C:/Documents stop the exe, and delete the execution folder
not sure if this will help , but just this is my thought
There's no way to do this with a single process as the exe which you want to move is going to be running in memory.
You could make the application copy itself, execute the copy, then kill itself.
this will definitely need to be tweaked and is very basic, but hopefully will give you some idea. sorry that it's all statics in a console application, all the methods should be in their own appropriate class.
using System;
using System.Globalization;
using System.IO;
using System.Linq;
namespace StackExchangeSelfMovingExe
{
class Program
{
static void Main(string[] args)
{
// check if we are running in the correct path or not?
bool DoMoveExe = !IsRunningInDocuments();
string runningPath = Directory.GetCurrentDirectory();
if (DoMoveExe)
{
// if we get here then we are not, copy our app to the right place.
string newAppPath = GetDesiredExePath();
CopyFolder(runningPath, newAppPath);
CreateToDeleteMessage(newAppPath, runningPath); // leave a message so new process can delete the old app path
// start the application running in the right directory.
string newExePath = $"{GetDesiredExePath()}\\{System.AppDomain.CurrentDomain.FriendlyName}";
ExecuteExe(newExePath);
// kill our own process since a new one is now running in the right place.
KillMyself();
}
else
{
// if we get here then we are running in the right place. check if we need to delete the old exe before we ended up here.
string toDeleteMessagePath = $"{runningPath}\\CopiedFromMessage.txt";
if (File.Exists(toDeleteMessagePath))
{
// if the file exists then we have been left a message to tell us to delete a path.
string pathToDelete = System.IO.File.ReadAllText(toDeleteMessagePath);
// kill any processes still running from the old folder.
KillAnyProcessesRunningFromFolder(pathToDelete);
Directory.Delete(pathToDelete, true);
}
// remove the message so next time we start, we don't try to delete it again.
File.Delete(toDeleteMessagePath);
}
// do application start here since we are running in the right place.
}
static string GetDesiredExePath()
{
// this is the directory we want the app running from.
string userPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return $"{userPath}\\documents\\MyExe".ToLower();
}
static bool IsRunningInDocuments()
{
// returns true if we are running from within the root of the desired directory.
string runningPath = Directory.GetCurrentDirectory();
return runningPath.StartsWith(GetDesiredExePath());
}
// this copy method is from http://stackoverflow.com/questions/58744/best-way-to-copy-the-entire-contents-of-a-directory-in-c-sharp
public static void CopyFolder(string SourcePath, string DestinationPath)
{
if (!Directory.Exists(DestinationPath))
{
Directory.CreateDirectory(DestinationPath);
}
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*",
SearchOption.AllDirectories))
Directory.CreateDirectory(DestinationPath + dirPath.Remove(0, SourcePath.Length));
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*",
SearchOption.AllDirectories))
File.Copy(newPath, DestinationPath + newPath.Remove(0, SourcePath.Length), true);
}
private static void CreateToDeleteMessage(string newPath, string runningPath)
{
// simply write a file with the folder we are in now so that this folder can be deleted later.
using (System.IO.StreamWriter file =
new System.IO.StreamWriter($"{newPath}\\CopiedFromMessage.txt", true))
{
file.Write(runningPath);
}
}
private static void ExecuteExe(string newExePath)
{
// launch the process which we just copied into documents.
System.Diagnostics.Process.Start(newExePath);
}
private static void KillMyself()
{
// this is one way, depending if you are using console, forms, etc you can use more appropriate method to exit gracefully.
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
private static void KillAnyProcessesRunningFromFolder(string pathToDelete)
{
// kill any processes still running from the path we are about to delete, just incase they hung, etc.
var processes = System.Diagnostics.Process.GetProcesses()
.Where(p => p.MainModule.FileName.StartsWith(pathToDelete, true, CultureInfo.InvariantCulture));
foreach (var proc in processes)
{
proc.Kill();
}
}
}
}
I have an issue about mapped network drive.
I have 3 PCs: A, B and C. Each PC have a mapped network drive is Share2All(\Server)Z:, this drive point to a common folder on server, is Share2All folder.
I have an application which using FileSystemWatcher to monitor files on PC. This application is running on 3 PCs: A, B and C.
On A PC, when I edit and save a file which has path: Z:\test.txt (on mapped network drive), the changed event (of FileSystemWatcher) appear at same A, B and C PC.
I want, when I edit and save file Z:\test.txt on A PC, the changed event only appear on A PC.
To do this, I try to determine the last user who modified the file Z:\test.txt (is user on A PC), but it could not be.
Can anyone help me determine the last user who modified the file on mapped network drive, or give me any solution for my issue?
Thanks!
I haven't tried with this one, but It should work for you,
Create an extended class from FileSystemWatcher and assign a Tag value it.
public class ExFileWatcher : FileSystemWatcher
{
public ExFileWatcher(string filePath)
: base(filePath)
{
}
public ExFileWatcher(string filePath, string filter)
: base(filePath,filter)
{
}
public object Tag
{
get;
set;
}
}
and you can call it like,
ExFileWatcher fw = new ExFileWatcher("DirectectoryPath", "*.txt");
fw.Changed += fw_Changed;
//Assign a tag here differently on different machine.
fw.Tag = "1st machine";
fw.EnableRaisingEvents = true;
and in the changed event,
void fw_Changed(object sender, FileSystemEventArgs e)
{
if ((sender as ExFileWatcher).Tag == "1st machine")
{
//This is first machine.
}
else if ((sender as ExFileWatcher).Tag == "2nd machine")
{
//This is Second machine.
}
}