I'm trying to create a hashtable of filesystem watchers. This is to keep a running record of active filesystemwatchers with the directories they are watching as keys. Then via a form the user can add and delete folders to watch, which are visible in a listview or something.
My main problem is how to "keep" the hash table between methods and classes. I'm a bit of a novice to C# and it doesn't seem to work the way I'm used to in VB.NET.
So I have (stripped down to simplify):
public partial class MainForm : Form
{
public static Hashtable globalHashTable;
public MainForm()
{
InitializeComponent();
}
public void Button1Click(object sender, EventArgs e)
{
FileSystemWatcher watcher1 = new FileSystemWatcher(#"C:\");
globalHashTable.Add(#"C:\",watcher1);
}
}
}
So that a filesystemwatcher is added to the hashtable. However since the globalhashtable is static (?) this won't work. Making it non static means I have to create an instance of it when the buttton is pressed, so I have a new one each time as it's not "kept". My problem is how to keep a table in memory between methods and classes.
I'm fairly sure I've majorly misunderstood something as I'm new to all of this. Also I doubt this is even a half decent way to do this, if anyone has a better way, then please go ahead!
Thanks,
Matt
Expanding on #Ron Beyer's suggestion you can do something like this:
private Dictionary<string, FileSystemWatcher> _fileSystemWatcherMap;
public MainForm()
{
InitializeComponent();
_fileSystemWatcherMap = new Dictionary<string, FileSystemWatcher>();
}
public void Button1Click(object sender, EventArgs e)
{
string pathToWatch = #"C:\"; // Must be a different path each time otherwise will throw
var watcher = new FileSystemWatcher(pathToWatch);
_fileSystemWatcherMap.Add(pathToWatch, watcher);
}
This way all methods in the MainForm can access the file watchers.
If you need to share this among forms that are created from MainForm you can simply pass this data before showing the dialog.
If the other form is created in a different way the you can create a static class like this:
public static class FileWatcherMap
{
private static Dictionary<string, FileSystemWatcher> _fileSystemWatcherMap = new Dictionary<string,FileSystemWatcher>();
public static void AddWatcher(string path, FileSystemWatcher fsw)
{
_fileSystemWatcherMap.Add(path, fsw);
}
public static void RemoveWatcher(string path)
{
_fileSystemWatcherMap.Remove(path);
}
}
then in the click handler you add the watcher to this list:
public void Button1Click(object sender, EventArgs e)
{
string pathToWatch = #"C:\"; // Must be a different path each time otherwise will throw
var watcher = new FileSystemWatcher(pathToWatch);
FileWatcherMap.AddWatcher(pathToWatch, watcher);
}
Now FileWatcherMap class would be accessible from any other form
Related
So I am a beginner in software development and practicing C# in my time at home.
I have a project that I am working on and have reached a point where I am not sure how to code the functionality.
Imagine in my solution I have a winform UI with a dropdown. Inside that dropdown the user can make a choice and click a button to run a procedure. Depending on what the user has picked, it should initialize the class/object that is picked.
So the dropdown will have options such as; runOptionOne, runOptionTwo. If runOptionTwo is picked in the dropdown, upon clicking the button it will do:
runOptionOne runoptionone = new runOptionOne();
runoptionone.Doaction();
I do not want to have string checks on the dropdown as that will be loads of if statements.
Is there a technique or method to initialize a specific class based on user choice.
Combobox.Items accepts objects. For displaying, their ToString() method will be used.
This makes it possible to access the object directly via SelectedItem. As long as they share a common interface, it's easy to call a method on them.
private void button1_Click(object sender, EventArgs e)
{
var obj = (Interface) comboBox1.SelectedItem;
obj.DoSomething();
}
The other classes:
internal interface Interface
{
void DoSomething();
}
class Class1:Interface
{
public void DoSomething() { }
public override string ToString() => "Option 1"; // TODO: make translatable via resource
}
class Class2:Interface
{
public void DoSomething() { }
public override string ToString() => "Option 2"; // TODO: make translatable via resource
}
And initialization like
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add(new Class1());
comboBox1.Items.Add(new Class2());
}
I don't like this approach too much, since I consider the ToString() method to be rather developer oriented.
IMHO, a better approach is to have a dictionary with display strings as keys and objects as values. That way you also get rid of the if-statements and reduce cyclomatic complexity:
private readonly IDictionary<string, Interface> _displayItems = new Dictionary<string, Interface>
{
{"Option 1", new Class1()},
{"Option 2", new Class2()}
};
private void Form1_Load(object sender, EventArgs e)
{
foreach (var item in _displayItems)
{
comboBox1.Items.Add(item.Key);
}
}
private void button1_Click(object sender, EventArgs e)
{
var key = (string) comboBox1.SelectedItem;
_displayItems[key].DoSomething();
}
I know this might look silly but I got a strange problem in my winforms. I have a windows application in which after a particular set of operations are completed I want to populate a Checked ComboBox. I am doing this using two classes. I want to copy a array from helper class to the form class. Array gets copied when AddArrayItems method is called. But when I see the ComboBox in the form, its null. After debugging with watch variables I got to know that the problem is after copying the array to Form1 array, as soon the control goes back to the caller, the array items are deleted. I tried to replicate my stuff, not exactly but still similar to what I am doing.
My code looks like this:
using System;
using System.Windows.Forms;
namespace DemoApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string[] cboxAr;
public void AddCmboBoxItems(string[] cbArry)
{
cboxAr = new string[cbArry.Length];
Array.Copy(cbArry, 0, cboxAr, 0, cbArry.Length);
//cbArry.CopyTo(cboxAr, 0);
//foreach (string s in cboxAr)
//comboBox1.Items.Add(s);
comboBox1.Show();
}
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething();
}
}
public class HelperClass
{
public HelperClass()
{
}
public void HelperMethod()
{
SomeMethod();
}
private void SomeMethod()
{
string[] partnrName = new string[5] { "str1", "str2", "str3", "str4", "str5"};
Form1 f = new Form1();
f.AddCmboBoxItems(partnrName);
}
public static void DoSomething()
{
new HelperClass().HelperMethod();
}
}
}
I don't understand what exactly the problem is here. Can anyone please push me in the right direction. Thanks in advance.
You're never showing the form after modifying its controls:
Form1 f = new Form1();
f.AddCmboBoxItems(partnrName);
But you're calling this from within an existing form:
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething();
}
Presumably you want to modify the controls on that form? Then you'll need a reference to that form. Pass one to the method:
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething(this);
}
And accept it in the method definition:
public static void DoSomething(Form1 form)
{
new HelperClass().HelperMethod(form);
}
And so until the point where you need to use it. (Side note: You have a lot of weird indirection happening here with a seemingly random mix of static and instance methods and classes. You can simplify a lot, which will make this involve fewer code changes.)
Ultimately, SomeMethod needs the instance of the form to modify:
private void SomeMethod(Form1 form)
{
string[] partnrName = new string[5] { "str1", "str2", "str3", "str4", "str5"};
form.AddCmboBoxItems(partnrName);
}
To illustrate the overall point, consider an analogy...
A car rolls off of an assembly line. You open the trunk and put a suitcase inside. Moments later another car rolls off of the same assembly line. It is identical to the first car in every way. When you open the trunk of the second car, do you expect to find your suitcase inside it?
A Form is an object like any other. Changes made to one instance of an object are not reflected in other instances of the same object. Each instance maintains its own state. In order to modify a particular instance, you need a reference to that instance.
I am brand new to C# (I apologise if my question is noobish - I'm teaching myself, so it's a bumpy process). I am trying to develop a winform and since some of the methods are pretty long, I am trying to keep it in a couple classes. This is what I'm kind of hoping to achieve:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1();
}
}
public class longCalculations
{
private void LongMethod1()
{
// Arbitrarily long code goes here
}
}
I'm doing this in an attempt to keep the formMainForm class tidy and be able to split any calculations into manageable chunks. However, I'm encountering problems with using form controls (e.g. check boxes, numeric up-down controls, etc.) in my non-form classes.
If I leave them as is (e.g. CheckBox1) I get a the name does not exist in the current context error. I searched around and I found that it's because that box is defined in a different class. However, if I change it to formMainForm.CheckBox1, the error is now an object reference is required for the non-static field, method or property. Again, I looked around and it appears that that is due to the form initialization method not being static.
If I change public formMainForm() to static formMainForm(), the error now moves to InitializeComponent(); and I do not know where to go from here. I also tried making an instantiation of the formMainForm() method, but that didn't do anything (the code I attempted to use is below. I found it somewhere on this site as an answer to a similar problem).
private void formLoader(object sender, EventArgs e)
{
shadowrunMainForm runForm = new shadowrunMainForm();
runForm.Show();
}
How can I use the formcontrol names in other classes?
P.S. It is my first post here - I am super sorry if I have missed this question already being asked somewhere. I did search, but I didn't find what I was looking for.
EDIT
It seems I hadn't made myself clear - this was just an example of code and my problem is with the second class, not the first one. I have now simplified the code to:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
}
public class longCalculations
{
private void LongMethod1()
{
List<CheckBox> listOfBoxes = new List<CheckBox>();
listOfBoxes.Add(CheckBox1);
// The code displays an "object reference is required for the non-static field, method or property" error at this stage. Changing the "CheckBox1" to formMainForm.CheckBox1 doesn't help
// Arbitrarily long code goes here
}
}
LongMethod1 works perfectly fine when placed in the formMainForm partial class. Moving it to the other form makes it unable to take data from those checkboxes.
I believe this line longCalculations.LongMethod1(); is throwing error cause you are trying to access a instance method as if it's a static method and as well it's defined as private method which won't be accessible outside the class. You need to create an instance of longCalculations class before accessing any of it's member or method(s) and mark the method public like
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations ln = new longCalculations();
ln.LongMethod1();
}
public class longCalculations
{
public void LongMethod1()
{
// Arbitrarily long code goes here
}
}
(OR) If you really want it to be a static method then define accordingly with static modifier like
public class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
Now you can call it like the way you are trying
public static class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
If you're going to make a call longCalculations.LongMethod1();, then you need to make your class static as such.
Or you leave it as not static method by calling
longCalculations lc = new longCalculations()
lc.LongMethod1();
As for accessing controls in separate classes, you can pass in the form and make the controls public which can be dangerous.
So on your Form.designer.cs, change any control you may have to public modifier. Then you would make a call like this...
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1(this);
}
public void LongMethod1(Form1 form)
{
// Arbitrarily long code goes here
form.label1.Text = someString;
//more settings and whatnot
}
Or do something like this:
public class longCalculations
{
public string LongMethod1()
{
// Arbitrarily long code goes here
return myString;
}
}
longCalculations lc = new longCalculations()
string result = lc.LongMethod1();
this.label1.Text = result;
Ideally, your longCalculations class would not attempt to modify the form directly. Instead it would return an object that the form could use to update its controls.
If you need to access the form directly from the longCalculations class, first change the method to accept an instance of your form
public void LongMethod1(formMainForm myForm)
Then you can pass the form itself as a parameter
var calc = new longCalculations();
calc.LongMethod1(this);
In your other class, you need to have an instance of your formMainForm class:
var myForm = new formMainForm();
Then you can access its members like this:
myForm.CheckBox1.Checked = true;
I am trying to update picture box image inside "form1" from another cs file
my code inside test.cs
slot_13.modifier = public;
and inside form1 i wrote this also
CheckForIllegalCrossThreadCalls = false;
test.cs
inventory_Viewer.viewer x = new inventory_Viewer.viewer();
x.slot_13.Image = Image.FromFile(#"C:\Users\Axmed\Google Drive\C# Source Codes\inventory Viewer\inventory Viewer\bin\Release\icon\icon_default.png");
But it doesn't work
If i used this line inside "form1"
x.slot_13.Image = Image.FromFile(#"C:\Users\Axmed\Google Drive\C# Source Codes\inventory Viewer\inventory Viewer\bin\Release\icon\icon_default.png");
image gets changed
Your code misses a lot of context, so I'm going to do a few assumptions. Given a MainForm that shows the InventoryViewerForm and also wants to change the image on the InventoryViewerForm, you could hold a reference to the second form like this:
// Your inventory_Viewer.viewer
public partial class InventoryViewerForm
{
public InventoryViewerForm()
{
}
}
// The form from which to show the viewer.
public partial class MainForm
{
private readonly InventoryViewerForm _inventoryViewerForm;
public MainForm()
{
_inventoryViewerForm = new InventoryViewerForm();
}
private void ShowInventoryViewerButton_Click(object sender, EventArgs e)
{
_inventoryViewerForm.Show();
}
private void ChangeImageButton_Click(object sender, EventArgs e)
{
// Dispose the previously loaded image.
if (_inventoryViewerForm.Image != null)
{
_inventoryViewerForm.Image.Dispose();
}
_inventoryViewerForm.Image = Image.FromFile("NewImage.png");
}
}
But this is bad design altogether. You don't want to tightly couple your forms like this, and you want to leverage the data binding of WinForms and the events of .NET for this. In order to properly implement that, you'll need to show more code.
I have a C# Winforms Application and I'm using the main form to control the other this way:
public Rel_Entitys RelForm1;
public Struct_Inc StructForm1;
public DataLoad DataLoadForm1;
public Asset_Inc AssetForm1;
public Estimates_Inc EstimatesForm1;
public Options OptionsForm1;
private void Form1_Load(object sender, EventArgs e)
{
RelForm1 = new Rel_Entitys();
StructForm1 = new Struct_Inc();
DataLoadForm1 = new DataLoad();
AssetForm1 = new Asset_Inc();
OptionsForm1 = new Options();
EstimatesForm1 = new Estimates_Inc();
}
And then I access them this way:
private void barButtonItem6_ItemClick(
object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
StructForm1.Show();
this.Hide();
}
Is working fine for me to load data from database to this forms but when I try to get any value from any field they are null/empty. I already tried to use this.StructForm1.txt1.Text but nothing returns. What am I doing wrong? I use this form declaration to become more easy handle the form and call your methods but I not sure that is the right way to do it.
[Update]
I'm starting to think that is something related to my methods. If a set a value for the field on form_load and then get it from the method
public void SaveEstimate() {...}
It is empty again. Any ideas?
Looks like you are creating multiple instances of forms. Just a quick check. Make the fields static and then see if these are still Null(empty).
public static Rel_Entitys RelForm1;
public static Struct_Inc StructForm1;
public static DataLoad DataLoadForm1;
public static Asset_Inc AssetForm1;
public static Estimates_Inc EstimatesForm1;
public static Options OptionsForm1;
Make sure that the textbox you call txt1 is Public.
Select your textbox, go to the properties window, find Modifiers and set it to Public.