one winform to add and update data - c#

I usually in my web projects use one webform for adding and update data. I just scratched winforms environment so I was thinking to use same approach one form to add and update data.
I was thinking to use two constructors on addEditForm like
public AddEditForm()
{
.. to do new object
}
public AddEditForm(MyDataObj obj)
{
... to do edit
}
so, is this right approach or is there better practice?
thanks

As I said in my comment I use this approach too, of course when I'm not using MVP(which is a different story)
About calling InitializeComponent() you need it in your form construction because it is the method which (as you can tell from it's name) initializes your form and controls on it and without it you'll get an empty form.
But if you are concerned about calling InitializeComponent() twice, I prefer this:
MyDataObj _myObject;
public AddEditForm()
{
InitializeComponent();
}
public AddEditForm(MyDataObj obj)
:this()
{
if(obj == null) //you're creating the object
_myObject = new MyDataObj();
else // you're editing it
_myObject = obj;
}
// Continue my work with _myObject

You can create different constructors in the following way:
MyDataObj editItem=null;
public AddEditForm()
{
InitializeComponent();
//Other common code for initialization.
}
public AddEditForm(MyDataObj obj) : this()
{
editItem = obj;
//Other code specific to editing.
}
If the object editItem is null, then the form can be considered in Add mode, otherwise Edit mode.
A property also can be made for the same
For example:
public bool IsEditMode
{
get
{
return (editItem != null);
}
}
hope it helps...

The approach you posted is the normal approach for creating such a form.
But sometimes you will see something like this.
public AddEditForm(MyDataObj obj, int mode) //1 = edit, 2 = create
{
... to do edit
}
If you think about it, this is not a good alternative. It's harder to understand and looks ugly.
Do I need to call InitializeComponent() in every constructor?
Unless you do constructor chaining (which would not work here), yes you do.
Please look #Virus answer for a way to only call it once.

The correct approach would be:
public partial class CustomerForm: Form
{
private object instance;
public CustomerForm()
{
InitializeComponent();
SetData(BLL.CreateNewEmptyObject());
}
public CustomerForm(object details)
: this()
{
SetData(details);
}
public void SetData(object details)
{
instance = details;
//bind the details to controls
}
private void Save()
{
BLL.Save(instance);
}
public bool EnableEdit {get{...
}
Usage Examples:
var newCustomerFrm = new CustomerForm();
var existingCustomerFrmReadOnly = new CustomerForm(BLL.GetCustomerById("123"))
{
EnableEdit = false
};
var existingCustomerFrmToEdit = new CustomerForm(BLL.GetCustomerById("123"))
{
EnableEdit = true
};

Related

Control on another form is inaccessible due to it's protection level

TF2SelectDir.txtTF2DirSelect.Text = "";
This is giving me issues, as txtTF2DirSelect is on one form and I'm trying to change it from another. I tried looking it up, and the entire form itself is already public, not private.
Or, to go along with this, how can I create a variable that can be accessed on any form?
Where it goes wrong
if (canFindTF2 == true)
{
TF2SelectDir.txtTF2DirSelect.Text = "";
The form where TF2SelectDir is is already public
public partial class TF2SelectDir : Form
{
public TF2SelectDir()
{
InitializeComponent();
}
Any ideas? Thanks!!
UPDATE
At the bottom of my TF2SelectDir.Designer.cs, I've found
private System.Windows.Forms.TextBox txtTF2DirSelect;
private System.Windows.Forms.Button btnSaveTF2Dir;
private System.Windows.Forms.Label lblExample;
However, when I changed private to public on txtTF2DirSelect, I got a new error.
"An object reference is required for the non-static field, method, or property 'TF2SelectDir.txtTF2DirSelect' - Error Code CS0120
Since I cannot comment, I am posting this as an answer.
Accessing controls from a separate form, may not be the best idea. I would recommend you use properties. Here is Microsoft's definition and usage example of properties.
Another, even better way, in my opinion, to share data between two forms, is to use events. Once again, here is Microsoft's description of events.
If you need a working example of how to use either of these approaches, I would like to see your effort first and then we can build on that.
Expose control in below way .. why?? #monstertjie_za provided few good links on that already .
namespace TF2Overwatch
{
public partial class TF2SelectDir : Form
{
//Approch 1 - usable when the projects most works are done
//without following a good architecture
//You can use a static variable to preserve the state and intilize each time
//a new instance is created
//Approch 2 - Responibilty of preserving text to initlize in textbox should be taken
//by the form who calling this form
//value will pass by consturtor or by exposing property
//all approch 2 code are kept commented for better understanding
private static string strTxtTF2DirSelectTextToInitize;
public TF2SelectDir()
{
InitializeComponent();
txtTF2DirSelect.Text = strTxtTF2DirSelectTextToInitize;
}
public static string TxtTF2DirSelectTextToInitlize
{
get
{
return strTxtTF2DirSelectTextToInitize;
}
set
{
strTxtTF2DirSelectTextToInitize = value;
}
}
//public TF2SelectDir(string txtTF2DirSelectText)
//{
// InitializeComponent();
// txtTF2DirSelect.Text = txtTF2DirSelectText;
//}
//public string TxtTF2DirSelectTextToInitlize
//{
// get
// {
// return txtTF2DirSelect.Text;
// }
// set
// {
// txtTF2DirSelect.Text = value;
// }
//}
}
public partial class SomeAnotherForm:Form
{
public SomeAnotherForm ()
{
InitializeComponent();
}
protected void InSomeAction(object Sender, EventArgs e)
{
if (canFindTF2 == true)
{
TF2SelectDir.TxtTF2DirSelectText = "Test";
TF2SelectDir t1 = new TF2SelectDir();
t1.Show();
//Approch 2
//TF2SelectDir t1 = new TF2SelectDir("Test");
//t1.Show();
//TF2SelectDir t1 = new TF2SelectDir();
//t1.TxtTF2DirSelectText="Test"; //look here TxtTF2DirSelectText is setting on instance not by class
//t1.Show();
}
}
}
}

c# sharing a class between multiple forms

I have been looking around and found some answers with the same question as me, however i did try the code and it didn't work in my case.
I tried to do the same thing as this. My aim is to enable many different forms to use a class to do something.
Here are the part of simplified version of my class:
public class test
{
somedll g = new somedll();
somedll h = new somedll();
public void Stop(int module)
{
string command = "STOP";
if (module == 1)
{
this.WriteCommand(1, command);
}
else if (module == 2)
{
this.WriteCommand(2, command);
}
}
private void WriteCommand(int module, string command)
{
try
{
if (module == 1)
{
g.write(command + '\r');
}
else if (module == 2)
{
h.write(command + '\r');
}
}
catch (Exception)
{
if (module == 1)
{
gconnected = false;
}
else if (module == 2)
{
hconnected = false;
}
MessageBox.Show("<Write failed> Please connect.");
}
}
As my problems is i am unable to use static to make my class to be able to shared by all forms, as static is more efficient in just sharing variable/data.
edit*: I dont actually need static, i just need to make this class accessible from all other forms, without declaring new instances, i mentioned static because i did tried to used it and it cant compile.
The problem with not creating multiple instances is due to i need the data to be centralized. As declaring multiple instances cause all forms to get independent data.
edit*: My aim is to use this class that i show above with other forms without creating new instances from each forms. For example, in each form1, form2, form3 and form4, i will need to access 'stop', and then stop will in turn call 'writecommand' to finally send out the command. So, due to there is some calling in the method, static is unable to use(in my field of knowledge in c# only
Is there anyway to solve this? thanks
You can pass a single instance of your class to multiple forms (either through the constructor or via a property). However, you will probably need to make your class thread-safe by using locking.
A static instance of your non-static class would be another way for your forms to access a single instance, but this is not usually the best approach as it more tightly couples the class and the forms.
EDIT
To expand, a static instance of your non-static class Could look like this:
public class test
{
private static test singleInstance = new test();
public static test SingleInstance { get { return singleInstance; } }
somedll g = new somedll();
somedll h = new somedll();
public void Stop(int module)
{
// ...
}
private void WriteCommand(int module, string command)
{
// ...
}
}
Or it could be in another class altogether.
The other (possibly better) approach would be to create a new instance in the code that creates your forms, and to pass it to the forms' constructors, which could be edited to be something like this:
class MyForm : Form
{
private readonly test testInstance;
public MyForm(test testInstance)
{
this.testInstance = testInstance;
}
}
As I understand, you want to create an instance of your class, change it's value from one form and want the changed value of this instance to be reachable from other forms. You said you cannot use static for that, but I think you can. Have you tried using a static class like:
static class YourClass
{
private static string _yourVar= "";
public static string YourVar
{
get { return _yourVar; }
set { _yourVar = value; }
}
}
and change it like:
YourClass.YourVar = "your value"
I highly recommend reading this thread.

Issue while invoking a form from another using System.Window.Forms.Invoke(delegate)

I have two forms and 1 singleton class. I am initalizing the singleton class in btn_A_Click of formA.
public partial class frmA : Form
{
public frmA()
{
InitializeComponent();
frmB frmB;
}
private void btn_A_Click(object sender, EventArgs e)
{
SessionMgmt.GetInstance().StartFormB();
}
}
This is my singleton class and here I am trying to use Forms.Invoke() method.
public class SessionMgmt
{
static SessionMgmt _sessinMgr;
frmB frB;
private SessionMgmt()
{
frB = new frmB();
}
public static SessionMgmt GetInstance()
{
if (_sessinMgr != null)
return _sessinMgr;
else
{
_sessinMgr = new SessionMgmt();
return _sessinMgr;
}
}
public bool StartFormB()
{
frB.Invoke(new EventHandler(DisplayFrmB));
return true;
}
private void DisplayFrmB(Object o, EventArgs e)
{
frB.Visible = true;
frB.Refresh();
}
}
This is my formB.
public partial class frmB : Form
{
}
But from the frB.Invoke(new EventHandler(DisplayFrmB)); method it throws the following exception:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
I can't figure out the issue, please help or advice me if I miss anything.
EDIT
The following structure is the way my current project is displaying the next form. It was done by VB.NET and I need to use similar kind of thing in the new project which uses C#. I saw the Invoke function which points to an event and then to a function. In that function it just makes the Form.Visible=true and Form.Refresh. But for understanding I just tried a POc and followed the same steps ,but it is not yet solved.
What is reason to call invoke? Isn't this doing the job for you?
public bool StartFormB()
{
frB.Visible = true;
return true;
}
Windows Forms is a wrapper around the Windows API, and that exception means the underlying window hasn't been created yet. I think it gets created when you set Visible to true for the first time, and there are a few other situations that do it.
See this link for a possible solution: http://blogs.msdn.com/b/mapo/archive/2011/04/27/forcing-handle-creation-in-a-net-windows-forms-control.aspx
there are two possible reasons for that exception:
The form isn't created when the invoke is called
It's possible that you're creating your controls on the wrong thread
you should always check the InvokeRequired Property before Invoking, and of course check for null before that
public bool StartFormB()
{
if (frB == null)
{
throw new ArgumentNullException("frB");
}
if (frB.InvokeRequired)
{
frB.Invoke(new EventHandler(DisplayFrmB));
}
else
{
if (frB.IsDisposed)
{
throw new ObjectDisposedException("Control is already disposed.");
}
}
return true;
}
Control handle IS NOT created if the control's Visible property is false. When you call Invoke you set your controls visible state to true in delegate, but handle is not created yet, so you can not call Invoke. So - you must call frB.CreateHandle(); after: frB = new frmB(); to force creation of control handle
private SessionMgmt()
{
frB = new frmB();
var h = frB.Handle;
}

Change value of control on a form from class (C#)

This should be quite simple really - not sure what the problem is.
I have a C# Class (Public.cs) and a windows form (Form1.cs). Through a function in Public.cs, I want to get the value of a control on Form1 (without having to use object parameters).
// This code appears in Public.cs
public string MyFunction(int num_val)
{
if (chk_num.checked == true)
{
// Something here...
}
}
The issue is that my class cannot find the control on my form. Is there some way that I must reference it in C#?
Thank you.
I would strongly suggest exposing the Checked property via a specific property on Form1 (perhaps with a more meaningful name). This will help to hide the implementation details (i.e. control structure) of the Form1 from it's caller and instead expose only the logic that is required for other consumers to do their job
For example:
public bool IsNumberRequested
{
get { return chk_num.Checked; }
}
Or alternatively, if you still really want to access the control directly, from the designer you can select the control and change it's Modifier property to public (or something else) enabling you to access the control object using the code you originally wrote above.
EDIT: (Response based on comment)
Public.cs will still need a reference to Form1 and then will call the IsNumberRequested property of that object.
// Public.cs
public class Public
{
private Form1 _ui;
public Public(Form1 ui) { _ui = ui };
public string MyFunction(int num_val)
{
if (_ui.IsNumberRequested)
{
// Stuff
}
// Else, default Stuff
}
}
Alternatively, you could pass the form as a parameter to the MyFunction too rather than using it as an instance variable.
I would have the set up the other way around
public class Public
{
public bool CheckNumber {get;set;}
public string MyFunction(int val)
{
if(CheckNumber)
{
//do that thing
}
return ...
}
}
public partial class Form1 : Form
{
Public myinstance = new Public();
public Form1()
{
InitializeComponent();
}
private void CheckBoxChanged(object sender, EventArgs e)
{
myinstance.CheckNumber = chk_num.checked;
}
}
You'll need to assign CheckBoxChanged to the OnChanged event handler for your check box (which I'm assuming is chk_num.
This way your class Public doesn't rely on a form, which it shouldn't.
As Reddog says, use better names, although I half suspect you've just given example names in your question.

access textbox from anywhere in application

How can I make a textbox in my winforms application that accepts new lines of text from anywhere in the application?
I have a main form that contains a textbox. I'd like to directly add text to the box from a method in another class.
Update
I tried this in my main form:
public void Output(String value)
{
if (txtOutput.Text.Length > 0)
{
txtOutput.AppendText(Environment.NewLine);
}
txtOutput.AppendText(value);
}
But I can't call Output from the other class. I'm new to C#, so perhaps I'm missing something obvious.
Regards, Miel.
PS Yes, I know this is bad design, but for now this seems to be the best way to do what I want. The textbox would function like a console.
You'll need to expose the Text property of the TextBox as a string property on your form. For example...
public string TextBoxText
{
get { return textBoxName.Text; }
set { textBoxName.Text = value; }
}
Edit
After reading the question edit, your problem is that you need a reference to a specific instance of the form whereever you're trying to execute that code. You can either pass around a reference (which is the better option), or you could use some smelly code and have a static property that refers to one instance of your form. Something like...
public partial class MyForm : Form
{
private static MyForm instance;
public static MyForm Instance
{
get { return instance; }
}
public MyForm() : base()
{
InitializeComponent();
// ....
instance = this;
}
}
Using this approach, you could call MyForm.Instance.Output("test");
In order to decouple a bit more you could inverse the control a bit:
// interface for exposing append method
public interface IAppend
{
void AppendText(string text);
}
// some class that can use the IAppend interface
public class SomeOtherClass
{
private IAppend _appendTarget = null;
public SomeOtherClass(IAppend appendTarget)
{
_appendTarget = appendTarget;
}
private void AppendText(string text)
{
if (_appendTarget != null)
{
_appendTarget.AppendText(text);
}
}
public void MethodThatWillWantToAppendText()
{
// do some stuff
this.AppendText("I will add this.");
}
}
// implementation of IAppend in the form
void IAppend.AppendText(string text)
{
textBox1.AppendText(text);
}
It looks like your design is a little bit corrupted. You shouldn't let buisness logic mess with GUI controls. Why don't you try a return value and assigning it on the interface side?
This is a REALLY bad way of doing it, but just to make sure all the answers are out there...
In the VS designer, each form control has an item in the Properties window named Modifiers that defaults to Private. Changing this to one of the others settings, such as Internal or Public, will let you access it from outside the form.
I must stress that this is the worst way to do it.

Categories