Call non static method from partial class - c#

I have two forms in the same namespace.
One is the main form that displays the list of accounts.
public partial class Server : Form
{
public Server()
{
InitializeComponent();
LoadAcounts();
}
public void LoadAcounts()
{
AccountDB acc = new AccountDB();
userListBox.DataSource = acc.ListUsers();
this.userListBox.SelectedIndex = 0;
}
}
Second is the registration form.
public partial class RegForm : Form
{
public RegForm()
{
InitializeComponent();
passBox.Text = "";
passBox.PasswordChar = '*';
passBox.MaxLength = 14;
passBox2.Text = "";
passBox2.PasswordChar = '*';
passBox2.MaxLength = 14;
}
private void button1_Click(object sender, EventArgs e)
{
if (passBox.TextLength >= 4 && passBox.Text == passBox2.Text && usernameBox.TextLength >= 4)
{
AccountDB acc = new AccountDB();
if (acc.UserExist(usernameBox.Text))
{
MessageBox.Show("User already exists!");
}
else
{
string user = usernameBox.Text;
string pw = PasswordHash.HashPassword(passBox.Text);
WriteDB(user, pw);
this.Close();
MessageBox.Show("Registration successful!");
//LoadAccounts();
}
}
}
}
I am currently stuck on how can I call LoadAccounts() after Registration successful so the userListBox will be refreshed to include the newly added account.

I am not sure about your design, but you can create an instance property of the "Server" class in your "RegForm" class. BUT, I should say that is increasing class coupling and definitely is not a good pattern.
public partial class RegForm : Form
{
public Server serverFormInstance {get; set;}//must be filled from caller code
...
...

If you have only one instance of the Server form, you can make it as a singleton to be able to call the method.
public class Server : Form
{
static internal readonly Server Instance = new Server ();
private Server()
{
InitializeComponent();
LoadAcounts();
}
}
Or any singleton implementation you like.
So you'll change all access to Server by Server.Instance.
Now you can call:
Server.Instance.LoadAcounts();
But if you plan to allow several instances of Server, a registration method may be used but it requires more code of your project to think about that.
You can also read this:
Communicate between two windows forms in C#

Related

how to access array from one class to another class in C# winforms?

I want to access array from one class to another class because my end-user enter the name list on one class. That list store into array in the same class. Then that name list access from another class. I'm not getting any errors in compile time. only I'm getting a run time error. I'm literally sorry to all coz I'm absolutely noob :(
public partial class custom : Form //class one which is end user enter the name list
{
public string PresentValue;
public string NormalValue;
public string[] PValue = new string[50];//public array
public string[] NValue = new string[50];//public array
}
public static int PresentArray = 0;// this line is used to increment the array index
private void cstmsvbtn_Click(object sender, EventArgs e)//this line enter the user namelist
{
PresentValue = cstmtst1.Text + "_PV";//concatinate '_PV'
NormalValue = cstmtst1.Text + "_NV";//concatinate '_NV'
PValue[PresentArray] = PresentValue;
NValue[PresentArray] = NormalValue;
PresentArray++;
}
public partial class print : Form // class to which is end user want to access that name list
{
custom customarray = new custom();// I instantiate the custom cass object
private void button1_Click(object sender, EventArgs e)//when i press this button message box show an empty white box only
{
MessageBox.Show(CustomArray.PValue[0],CustomArray.NValue[0]);
}
}
This is a common requirement and there are many ways to achieve this outcome (some of which might be considered "hacky"). Things I don't recommend:
Changing visibility to public for data fields that should be private
Creating tight dependencies of one form to the implementation details of another.
Creating "global" variables using the static keyword.
Since you claim to be a "noob" I'd like to suggest learning about the event keyword and using Events to communicate between forms. Yes, there is a small learning curve here, but chances are you'll use this a lot and it will be a good investment. I put a link in the Comments section so you can clone or browse this example and see if it does what you want it to (I recommend setting debugger break points so you can see why it does what it does).
What you have (according to your post) is a print form and a custom form. And though you don't really say, this example will have a MainForm that can show the other two:
PrintForm
The PrintForm requires the NValue and PValue arrays to do its printing. By declaring an event named ArrayRequest we give it the ability to request these arrays. Importantly, this class doesn't need to have any knowledge of where this information might be coming from.
public partial class PrintForm : Form
{
public PrintForm() => InitializeComponent();
This is how the class can initiate the request
public event ArrayRequestEventHandler ArrayRequest;
protected virtual void OnArrayRequest(ArrayRequestEventArgs e)
{
ArrayRequest?.Invoke(this, e);
}
When the button is clicked, try and get the information by callingOnArrayRequest
private void buttonShowArray_Click(object sender, EventArgs e)
{
ArrayRequestEventArgs req = new ArrayRequestEventArgs();
OnArrayRequest(req);
if(req.Count == 0)
{
MessageBox.Show("Invalid Request");
}
else
{
String[] allValues =
Enumerable.Range(0, req.Count)
.Select(index => $"{req.NValue[index]} | {req.PValue[index]}")
.ToArray();
MessageBox.Show(
text: string.Join(Environment.NewLine, allValues),
caption: "All Values"
);
}
}
}
// Defined outside the PrintForm class
public delegate void ArrayRequestEventHandler(Object sender, ArrayRequestEventArgs e);
public class ArrayRequestEventArgs : EventArgs
{
public int Count { get; set; }
public string[] PValue { get; set; }
public string[] NValue { get; set; }
}
CustomForm
The CustomForm as shown in your post is the class that contains the arrays.
public partial class CustomForm : Form
{
public CustomForm()
{
InitializeComponent();
}
We give this class the ability to fulfill a request for the arrays.
internal void ArraysRequested(object sender, ArrayRequestEventArgs e)
{
e.Count = _presentArray;
e.NValue = _nValue;
e.PValue = _pValue;
}
The data held in this class should be private.
// These should all be private
// See naming conventions: https://stackoverflow.com/a/17937309/5438626
// Set up visual studio to do this automatically: https://ardalis.com/configure-visual-studio-to-name-private-fields-with-underscore/
private string _normalValue;
private string _presentValue;
private int _presentArray = 0;
private string[] _pValue = new string[50];//public array
private string[] _nValue = new string[50];//public array
private void cstmsvbtn_Click(object sender, EventArgs e)
{
_presentValue = $"{cstmtst1.Text}_PV"; //concatinate '_PV'
_normalValue = $"{cstmtst1.Text}_NV"; //concatinate '_NV'
// Make sure index doesn't exceed the size of the array
if ((_presentArray < _pValue.Length) && (_presentArray < _nValue.Length))
{
_pValue[_presentArray] = _presentValue;
_nValue[_presentArray] = _normalValue;
_presentArray++;
}
else MessageBox.Show("Array is Full");
Text = $"Custom: Count={_presentArray}";
cstmtst1.Text = $"Hello {_presentArray + 1}";
}
}
MainForm
It is the MainForm class that oversees the operations and "knows" how the forms should interact. The constuctor method is where the connection is made between the event fired by PrintForm and the fulfillment by the CustomForm.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// THIS IS THE "GLUE"
_printForm.ArrayRequest += _customForm.ArraysRequested;
}
private CustomForm _customForm = new CustomForm();
private PrintForm _printForm = new PrintForm();
// In MainForm.Designer.cs
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
_customForm.Dispose();
_printForm.Dispose();
}
base.Dispose(disposing);
}
private void buttonShowCustom_Click(object sender, EventArgs e)
{
_customForm.ShowDialog(owner: this);
}
private void buttonShowPrint_Click(object sender, EventArgs e)
{
_printForm.ShowDialog(owner: this);
}
}
You will need to adapt this to your specific requirements but hopefully this will give you some basics to go on.

Disable and Enable ToolStripMenuItem Programmatically

I'm setting up a User and Admin Permissions which works perfectly well but I want to disable some ToolStripMenuItem from "Users" but Enable them only for "Admin".
Here's the code that logs User and Admin in depending on their Roles.
if (dt.Rows[0][0].ToString() == "1")
{
if (ComboBox_LoginAs.SelectedIndex == 0)
{
this.Hide();
Main_Form mainSystem = new Main_Form();
mainSystem.Show();
}
else if (ComboBox_LoginAs.SelectedIndex == 1)
{
this.Hide();
Main_Form mainSystem = new Main_Form();
mainSystem.Show();
/* disable View All Employees for Users */
ViewAllEmployeesToolStripMenuItem.Enable = false;
}
I expect the Users to not be able to view all Employee Records except the Admin.
I hope this question will not get down voted.
Thank you for your help!!
Here is an example of an interface I used once that accomplishes something similar.
Main
namespace UnNamed Project
{
class Program
{
static void Main(string[] args)
{
User user;
user = new SuperUser("Bob", "12345");
if (user.Login())
{
Console.WriteLine($"Welcome {user.Name}");
}
else
{
Console.WriteLine("An error has occured.");
}
Utility.PauseBeforeContinuing();
}
}
}
Interface Class
namespace UnNamed Project
{
interface ILoginHandler
{
bool HandleLogin();
void SetPassword(string password);
}
}
User Class
namespace UnNamed Project
{
abstract class User
{
private string _name;
private int _securityLevel;
public User(string name, int securityLevel)
{
_name = name;
_securityLevel = securityLevel;
}
abstract public bool Login();
}
}
SuperUser Class
namespace UnNamed Project
{
class SuperUser : User
{
private ILoginHandler _loginHandler;
public SuperUser(string name, string password) : base(name, 10)
{
_loginHandler = new FaceLogin(password);
}
public override bool Login()
{
return _loginHandler.HandleLogin();
}
}
}
As you can see, if setup properly you can create an object "User" and another object "Admin" and then create an abstract method within user. You can alternatively do a virtual method to handle the login, just make sure that your admin class has an override for it's own Login() method. This will cause the program to use the method directly related to the object.
Okay, so I tried changing my MenuStripItem Modifier state to "public". Then I created an object on my main form.
public static Main_Form GetMainForm_Obj;
public Main_Form()
{
InitializeComponent();
}
Then inside my Form Load, I added:
private void Main_Form_Load(object sender, EventArgs e)
{
eMPLOYEESToolStripMenuItem.Enabled = true;
GetMainForm_Obj = this;
}
And finally, in my Login form:
if (ComboBox_LoginAs.SelectedIndex == 0)
{
this.Hide();
Main_Form mainSystem = new Main_Form();
mainSystem.Show();
}
else if (ComboBox_LoginAs.SelectedIndex == 1)
{
this.Hide();
Main_Form mainSystem = new Main_Form();
mainSystem.Show();
Main_Form.GetMainForm_Obj.eMPLOYEESToolStripMenuItem.Enabled = false;
}
Thank you everyone!

Why is my C# Singleton not working?

Im new to .net and this is also my first post here so apologies in advance for any newb mistakes I may be doing:)
Background of the problem.
I’m working on a C# project and as part of it I have to store windows form data onto a database. I am using a data class “person” to transport the windows form data to a class responsible for accessing the database on the windows forms behalf. I wish to use the Singleton pattern on the windows forms code to prevent multiple instances of the window from existing.
Problem
In the save buttons event handling code I wish to create a “Person” object, populate it with user entered values and send it to be saved onto the database. The problem occurs here. The “Person” object does not get populated!
I’ve tried doing this in another form where I have not modified the code to accommodate the singleton pattern and that works.
So what am I doing wrong here? Is there a way for me to still keep the singleton pattern and make it work?
Window Form Code
namespace AgTrain
{
public partial class CreateAdmin : Form
{
private static CreateAdmin instance;
private CreateAdmin()
{
InitializeComponent();
}
private void CreateAdmin_Load(object sender, EventArgs e)
{
}
public static CreateAdmin getInstance()
{
if(instance==null)
{
instance = new CreateAdmin();
instance.InitializeComponent();
}
return instance;
}
public void makeInstanceNull()
{
instance = null;
}
private void button1_Click(object sender, EventArgs e)
{
Person personToBeSaved = new Person();
PersonDAO personDAO = new PersonDAO();
personToBeSaved.FirstName = textBox1.Text;
personToBeSaved.LastName = textBox2.Text;
personToBeSaved.Address = textBox3.Text;
personToBeSaved.TelNo = textBox4.Text;
personToBeSaved.UserName = textBox5.Text;
personToBeSaved.Password = textBox6.Text;
personToBeSaved.UserType = "admin";
personDAO.addPerson(personToBeSaved);
}
}
}
Caller Code
private void createAdminToolStripMenuItem_Click(object sender, EventArgs e)
{
CreateAdmin creAdmin = CreateAdmin.getInstance();
creAdmin.Closed += (s, ex) => { creAdmin.makeInstanceNull(); };
creAdmin.MdiParent=this;
creAdmin.Show();
}
Thanks.
Dumidu
You are calling InitializeComponent twice.
Try that:
private static CreateAdmin _instance;
public static CreateAdmin Instance
{
get { return _instance ?? (_instance = new CreateAdmin()); }
}
In my opionion is thefiloe's solution the cleanest, but there is a further possibility to introduce (effective) singletons in C#:
public static readonly CreateAdmin Instance = new CreateAdmin();
Client Code:
CreateAdmin.Instance.DoSomething()
But as already mentioned I recommend thefiloe's way!

C# Multiple class events

Im making a program what connects to multiple 3th party systems. The connect with different formats so i created multiple classes to deal with them. I have now three 4 classes.
The MainForm is the first class. This is the basic windows form class with the user interface.
SDKCommunication is the second class.
VMS (this class handles the events given of by the 2th party system and activates methods on SDK COmmunication)
Events
Events Class
public class Events
{
public event EventHandler LoginStateChanged;
private bool loginstate;
public bool LogInState
{
get { return this.loginstate; }
set
{
this.loginstate = value;
if (this.LoginStateChanged != null)
this.LoginStateChanged(this, new EventArgs());
}
}
}
part of SDKCommunicatie class
Events events = new Events();
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
MainForm Class
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
When the LogInState Changes in the SDKCommunicatie class. There needs to be an event fired in the MainForm class. But sadly that doesn't work.
But when I change the loginstate in the mainform(with a buttonclick)(see code below) the event is fired. But that is not the intention i would like to have.
private void button1_Click(object sender, EventArgs e)
{
events.LogInState = true;
}
If my question isn't clear enough, please let me know.
VMS class Added as reply to #Astef
class VMS {
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(MainForm));
GxUIProxyVB m_UIProxy = new GxUIProxyVB();
public string username2;
public string directory2;
public string Status;
public void initOmni()
{
m_UIProxy.CreateInstance();
m_UIProxy.OnLogon += new _IGxUIProxyVBEvents_OnLogonEventHandler(m_UIProxy_OnLogon);
m_UIProxy.OnLogoff += new _IGxUIProxyVBEvents_OnLogoffEventHandler(m_UIProxy_OnLogoff);
m_UIProxy.OnError += new _IGxUIProxyVBEvents_OnErrorEventHandler(m_UIProxy_OnError);
m_UIProxy.OnAlarmStatusEx2 += new _IGxUIProxyVBEvents_OnAlarmStatusEx2EventHandler(m_UIProxy_OnAlarmStatusEx2);
}
public void login(string username, string password, string directory)
{
username2 = username;
directory2 = directory;
initOmni();
m_UIProxy.LogOn(directory, username, password,false);
}
public void logOff()
{
m_UIProxy.LogOff();
}
void m_UIProxy_OnLogon()
{
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
sdkcommunicatie.onLogon(username2, directory2, "Genetec Omnicast");
}
I have fixed this with deleting the following:
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
And adding the following in the base of VMS:
SDKCommunicatie sdkcommunicatie;
But now i got a new error in the mainform when i tried to call a class in SDKCommunicatie
connectedStatus = sdkcommunicatie.connectedStatus();
I got the following error:
NullReferenceException was unhandled
You are not using the same instance of the Events class, and that's why on button click you catch LoginStateChanged. You should inject the same instance of Events class to SDKCommunicatie class, then you'll be able to listen to event changes.
Edit:
Jeremy Todd and I were both writing at the same time.
Events in your SDKCommunicatie are not fired because you've created an individual instance of class Events for it. That is not the instance you have placed on the MainForm.
Inject the right instance (pass a reference) to SDKCommunicatie from MainForm through constructor, property or somehow else. For example:
MainForm:
SDKCommunicatie sdkcommunicatie;
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
sdkcommunicatie = new SDKCommunicatie(events);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
SDKCommunicatie:
Events events;
public SDKCommunicatie(Envents eventsInstance)
{
events = eventsInstance;
}
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
Your SDKCommunication class and your MainForm class each have their own separate instance of Events, so any events you trigger from one won't be visible from the other -- they're being raised on an entirely different object.
What you need is a single instance of the Events class that both SDKCommunication and MainForm can share -- that way they'll both be seeing the same thing. There are several different approaches you could take for this. Depending on what it needs to do, one very simple possibility might be to make Events a static class, and then the events would be visible everywhere without needing to create any instances.
I have solved the riddle.
When i need a method is a class i can call the method directly like this:
public class MainForm : Form
{
SDKCommunication sdkcommunication = new SDKCommunication();
public MainForm()
{
}
private void Button1_Click(oject sender, EventArgs e)
{
sdkcommunication.method("Test")
}
}
This is pretty straightforward. Look here the receiverclass:
public class SDKCommunication
{
method(string word)
{
//do something with word
}
}
The biggest problem is calling the class with the form(the original class). I have solved this with a eventhandler.
class CustomEventHandler1 : EventArgs
{
public CustomEventHandler1(string u, string d)
{
msgu = u;
msgd = d;
}
private string msgu;
private string msgd;
public string Username
{
get { return msgu; }
}
public string Directory
{
get { return msgd; }
}
}
Then the SDKCOmmunication class should look like this:
class SDKCommunication
{
public event EventHandler<CustomEventHandler1> RaiseCustomEventHandler1;
protected virtual void OnRaiseCustomEventHandler1(CustomEventHandler1 e)
{
EventHandler<CustomEventHandler1> handler = RaiseCustomEventHandler1;
if (handler != null)
{
handler(this,e);
}
}
//Custom Method that is called somewhere
internal void custommethod()
{
OnRaiseCustomEventHandler1(new CustomEventHandler1("johnsmith", "localhost");
}
}
Then in the mainform class:
public class MainForm : Form
{
public MainForm()
{
sdkcommunication.RaiseCustomEventHandler1 += new EventHandler<CustomEventHandler1>(sdkcommunication_RaiseCustomEventHandler1);
}
void sdkcommunication_RaiseCustomEventHandler1(object sender, CustomEventHandler1 e)
{
//Do something.
}
}
The information sended with the event you can get with e.Username and e.Directory. In this example they are strings where e.Username = johnsmith and e.Directory = localhost.
I hope somebody can use this information for their own code.

Is it possible to pass a class as an argument when the same class has initialized?

Class:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
public class MainService : IChat
{
IChatCallback ChatCallback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
Chat chat = new Chat(this);
public void ShowChat()
{
chat.Show();
}
public void SendInstantMessage(string user, string message)
{
chat.RaiseMsgEvents(user, message);
ChatCallback.InstantMessage(user, message);
}
}
Form:
public partial class Chat : Form
{
MainService service;
public Chat(MainService service)
{
InitializeComponent();
OnMsgReceivedEvent += new OnMsgReceived(callback_OnMsgReceivedEvent);
this.service = service;
}
private void btnSend_Click(object sender, EventArgs e)
{
service.SendInstantMessage("Admin", txtMsg.Text);
}
}
The mainForm use the class like this:
public partial class Form1 : Form
{
ServiceHost host;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
host = new ServiceHost(typeof(WCF_Server.MainService));
host.Open();
}
}
In the main form, i just pass the class, no initializing, but in the class when ShowChat() called i need to show the chat form and get to this class method so i can send messages.
.NET is an object oriented language. In fact, every class is an object.
The error you are getting is because you're instantiating an object with "this" on the global level.
UPDATE
Based on your update you could do the following and it will work. You might want to refactor this some more to ensure that it's not going to break any business rules etc.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
public class MainService : IChat
{
IChatCallback ChatCallback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
//Changed this to be just a declaration. This will be null,
// as there is no object yet, this is really just a pointer to nothing.
//This tells the system that you might/are planning to use an object called
//chat, but it doesn't exist yet.
Chat chat;
// Get your default constructor going. This will create the actual chat object, allowing the rest of your class to access it.
public MainService()
{
//instantiate it! (or as some of our co-ops say "We're newing it")
chat = new Chat(this);
}
//now that chat is actually instantiated/created you can use it.
public void ShowChat()
{
chat.Show();
}
public void SendInstantMessage(string user, string message)
{
chat.RaiseMsgEvents(user, message);
ChatCallback.InstantMessage(user, message);
}
}
This is just a personal pet peeve, but having a function parameter the same name as a global variable is... well for me a no no. I noticed this on your Chat.Chat(MainService) function.
Of course it is, just create a method that takes this class of yours as a parameter and call it...
As other posts have suggested, you'll want to re-consider how you instantiate your chat field within your example class. I would consider lazy loading the property, like so...
private ChatForm _Chat = null;
private ChatForm Chat
{
get
{
if (this._Chat == null)
{
this._Chat = new ChatForm(this);
}
return this._Chat;
}
set { this._Chat = value; }
}
Using lazy-loading will ensure you're able to use the keyword this upon request.

Categories

Resources