winforms - suggested class structure and clone (not by reference) - c#

My program class has:
Application.Run(new Form1());
in form1 class I have:
model = new Model(this);
modelarray myArray = new modelarray(this);
model = myArray.models[0];
myArray.models[1] = (Model) model.Clone();
private void btn13_Click(object sender, EventArgs e)
{
model.btn13Clicked();
}
private void btnGetBackClone_Click(object sender, EventArgs e)
{
model = myArray.models[1];
//here I'm expecting to get the original object back (ie. with btns[7,7].Visible = True) but it doesn't work!!
}
in model class I have:
private Button[,] btns;
public Model(Form1 form1)
{
btns = new Button[10,10];
myform = form1;
btns[8, 6] = form1.btn1;
btns[9, 5] = form1.btn2;
btns[7, 7] = form1.btn13;
}
public void btn13Clicked()
{
btns[7, 7].Visible = False;
}
public object Clone()
{
return this.MemberwiseClone();
}
in modelarray class I have:
public Model[] models = new Model[19];
public modelarray(Form1 form1)
{
models[0] = new Model(form1);
}
Note my comment under the btnGetBackClone_Click method.
"//here I'm expecting to get the original object back (ie. with btns[7,7].Visible = True) but it doesn't work!!"
I understand that this is because models[0] and models[1] are pointing to the same memory location (ie copy by ref). But I am really lost at how to implement a solution in this situation. Searches on 'deep copy' did not seem to help as serializing a form didn't work. Can someone please correct my cloning error?
I know I could simply redo "btns[7, 7].Visible = True;" but I would like to know a cloning solution so it will copy all future fields I decide to put in my model.
I've had a search on codeproject.etc but there doesn't seem to be any straightforward intro to winforms.

.NET usually uses shallow copies during Clone operations.
In order to implement deep copies, you typically have 2 options
Serialize / deserialize (if your classes are all serializable) - e.g. Here
By using reflection e.g. Here
If you split your data (model) concerns out of your form (view), you can then more easily 'clone' just the data.

Related

Getting value pointer and use it from somewhere else

First , I'm a C++ dev and new to C# , Sorry for this simple question.
I'm creating a wrapper for my native library.
I want to pass a value in a class and edit it from some other function in class , like pointers in C++ , I found out it can be done with unsafe mode but I need to do it without unsafe and I'm sure it's possible.
Here's my code :
Main Console
namespace ConsoleApp2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string DATA_VALUE = "Not Set Yet";
new Data_Picker_Form(DATA_VALUE).ShowDialog();
Console.WriteLine("Value is {0}", DATA_VALUE);
Console.ReadKey();
}
}
}
Form Code
using System;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class Data_Picker_Form : Form
{
object data_in_obj;
public Data_Picker_Form(string data_in)
{
InitializeComponent();
data_in_obj = data_in;
}
private void button1_Click(object sender, EventArgs e)
{
string data_in_new = data_in_obj as string;
data_in_new = "OUTPUT_VALUE";
this.Close();
}
}
}
it's not working unfortunately , so I need to pass my string , int and etc. value to a new form , in initializing form creates a instance [like pointer] to original string and it can accessible from other functions ins class like button click.
thanks.
You already have a reference (sort of like a pointer), and that is your problem (well, half of it anyways).
string data_in_new = data_in_obj as string;
Says to create a variable that holds a string reference (as strings are immutable reference types) and copy the reference data_in_obj currently has to it. When you then reassign data_in_new it of course doesn't affect any other variable (just like it wouldn't in C++).
Because strings are immutable, there is no way for that code to affect other things that point to that string (passing by reference aside, but this is about variables/members). You need to store it in a simple struct or class so that everyone is pointing at an object that holds the current string reference, and can be updated.
Same idea with your int, it is actually a value type so any copy will copy the actual value, you can't change a different variable through it. You need a wrapper class so that each user is pointing at the same object.
What about setting up a simple get and set function since you are already Initializing your Form?
In Your Form:
private string data_in_new = "";
public Data_Picker_Form(string DATA_VALUE)
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Data_in_new = "OUTPUT_VALUE";
Close();
}
public string Data_in_new
{
get
{
return data_in_new;
}
set
{
data_in_new = value;
}
}
And in your Console:
class Program
{
static void Main(string[] args)
{
string DATA_VALUE = "Not Set Yet";
Data_Picker_Form D_P_T = new Data_Picker_Form(DATA_VALUE);
D_P_T.ShowDialog();
DATA_VALUE = D_P_T.Data_in_new;
Console.WriteLine("Value is {0}", DATA_VALUE);
Console.ReadKey();
}
}
This Way you can access you value at any desired point in the project.

How to access array defined in class in another class without constructor?

I have this code given by the API that I'm using.
public partial class getMerchant : object, System.ComponentModel.INotifyPropertyChanged
{
private int[] iMerchantIdField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("iMerchantId", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public int[] iMerchantId
{
get
{
return this.iMerchantIdField;
}
set
{
this.iMerchantIdField = value;
this.RaisePropertyChanged("iMerchantId");
}
}
}
Now I was trying to create an object of this class and to run it:
private void btnShowResult_Click(object sender, EventArgs e)
{
Awin.ApiPortTypeClient client = new Awin.ApiPortTypeClient();
UserAuthentication userAuthentication = new UserAuthentication();
userAuthentication.sApiKey = "111";
getMerchant merchant = new getMerchant();
merchant.iMerchantId[0] = 2518;
merchant.iMerchantId[1] = 3030;
var response = client.getMerchant(userAuthentication, merchant);
lblResult.Text = response[0].sName.ToString();
}
But whenever I try to run it it gives a nullreferenceexception when the compiler hit the line merchant.iMerchantId[0] = 2518;
What I understood so far is that this iMerchantId[] hasn't been declared yet. But the problem is also that I can't find an answer how to declare it.
I am thankful for any help that I can get.
To solve this initialize the backup property with required indices, which means the property definition would be like this:
private int[] iMerchantIdField= new int[2];
Need not to change the Public property, try using the current code, it will works fine without previous errors, since the bounds of the arrays are defined and initialized now through these backup properties.
Additional notes : If you deals with a List instead for an array, then you have to instantiate the list through the backup property, otherwise NullException will thrown. In such case the declaration would be :
private List<int> iMerchantIdField= new List<int>();

Public variable invoking incorrect result

public partial class ThanglishToTamilGUI : Form
{
public string anz;
public ThanglishToTamilGUI()
{
InitializeComponent();
}
public void btnConvertToBraille_Click(object sender, EventArgs e)
{
anz = richTextBoxTamil.Text.ToString();
GUI.TamilToBrailleGUI c1 = new GUI.TamilToBrailleGUI();
c1.Visible = true;
}
}
I need to pass my richtextbox (richTextBoxTamil) content to variable call anz.
I am retrriving anz variable in other form as form load event:
private void TamilToBrailleGUI_Load(object sender, EventArgs e)
{
ThanglishToTamilGUI tt = new ThanglishToTamilGUI();
String apper = tt.anz;
richTextBoxTamil.Text = apper;
}
My Problem:
I am getting null values as result. Since if I assigned any values that invoked correctly.
public partial class ThanglishToTamilGUI : Form
{
public string anz = "Hai";
public ThanglishToTamilGUI()
{
InitializeComponent();
} ...
Here my ans value is passed as "Hai". But my requirement is to get what ever the content in the richTextBoxTamil and pass it to that public variable call anz. What went wrong here please help me.
Thank you.
This is the problem:
ThanglishToTamilGUI tt = new ThanglishToTamilGUI();
String apper = tt.anz;
How do you expect apper to ever be anything other than null? You're fetching the variable from a freshly-created form, which has never been shown, and which has never had btnConvertToBraille_Click called on it.
Presumably there's an existing ThanglishToTamilGUI object somewhere, and that's the one you want to fetch the variable from. Basically, one form needs to know about the instance of the other form.
(I'd also strongly suggest using a property rather than a public variable, but that's a different matter. You might not even need to have a separate variable at all - just declare a property which fetches richTextBoxTamil.Text.)
Alternatively, just pass the relevant string to the constructor of the new form:
public void btnConvertToBraille_Click(object sender, EventArgs e)
{
GUI.TamilToBrailleGUI c1 = new GUI.TamilToBrailleGUI(richTextBoxTamil.Text);
c1.Visible = true;
}
Then the new form doesn't need to know about the old form at all - it only needs to know the text to display.
(You might want to pull it out of the constructor and into a settable property, but it's the same basically principle: the code creating the form pushes the data, rather than the new form pulling it.)
You can create a public property to access the current Text value of the textbox.
public string RichTextBoxText
{
get
{
return richTextBoxTamil.Text;
}
}
The way you do it now the form is instantiated, but the click event is not fired. So there's no way you will get anything other than what you initialized the field to.
Load is not the place to look for user input. An event (like click) is where you need to check the property value:
private void SomeClick(object sender, EventArgs e)
{
String result = thanglishToTamilGUIObject.RichTextBoxText;
//do something with text
}

Populating data in dropdown menu

I am new to c# so bit stuck at what I thought was a very simple module. I just need to display data in the dropdown menu but getting some error while binding... or I will say even before binding. Here is what I am trying to do..I am really sorry if I am doing a very simple mistake but I tried my best & now I think I need some guidance..
CustomService.cs
public partial class CustomService
{
public List<Code> GetDepartment(bool activeOnly)
{
List<Code> retVal = new List<Code>();
---some code----
return retVal;
}
}
ProgramList.ascx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
List<Code> dept = new List<Code>CustomService.GetDepartment(true);
ddlDepartment.DataSource = dept;
ddlDepartment.DataBind();
}
}
//error an object reference is required for an nonstatic field, method or Property CustomService.GetDepartment(true);
you forgot to create object first and than you can call the method
another thing is you just need to assign the value directly as i did below, there is no need to create any new list
check the code below that will work for you
CustomService custsrv = new CustomService();
List<Code> dept = custsrv.GetDepartment(true);
To be able to call the method GetDepartment, you need to have a new instance of CustomService created:
CustomService service = new CustomService();
service.GetDepartment(true);
or to make the method static:
public static List<Code> GetDepartment(bool activeOnly) { }
However, if you put it static, every variables used by that method that reside inside the class will also need to be static.
I think this would help.
CustomService custS = new CustomService();
ddlDepartment.DataSource = custS.GetDepartment(true);
ddlDepartment.DataBind();

winforms - point form to clone

My program class has:
Application.Run(new Form1());
in form1 class I have:
model = new Model(this);
private void userEnteredText()
{
Model clonedModel = (Model)model.Clone();
this.myButton.Size = new System.Drawing.Size(10,5);
MessageBox.Show("buttons made small");
this = clonedModel;
MessageBox.Show("clone complete and buttons restored to orig size");
}
in model class I have:
public Model(Form1 form1)
{
myform = form1;
}
public object Clone()
{
return new Model(myform);
}
My initial form1 object has the size of buttons really large. After the user enters a value in a textbox: I clone the model object and call a method that makes the buttons really small. How can I then set the model object to point back to the original model object with large buttons?
I'm getting this error:
"Cannot assign to this because it is read-only"
I know I can just change the button size but I need to clone the entire object because there are other original variables that I want reset.
One question - is it expected behaviour that whilst clone both models references the same Form? Clone() method just creates a new instance of Model but it still reference the same Form object,
You can persist state of the initial model in an other private field like
private Model backupModel;
and before applying a user-defined values just backup and later restore current model like:
private void userEnteredText()
{
this.backupModel = model;
Model clonedModel = (Model)model.Clone();
this.myButton.Size = new System.Drawing.Size(10,5);
MessageBox.Show("buttons made small");
model = this.backupModel;
MessageBox.Show("clone complete and buttons restored to orig size");
}

Categories