C# How to send multiple values to other form? - c#

I'm trying to send multiple values to a second form and display the text in a textbox without loosing the old values (every value in a new line), but i dont know how... Would be happy if somebody could help me :)
I searched everywhere to find a solution but couldn't find enything.
Code from data.cs
private static string Acc;
public static string GetAcc()
{
return Acc;
}
public static void SetAcc(string value)
{
Acc = value;
}
Code from Form 1
private void bunifuThinButton21_Click(object sender, EventArgs e)
{
Data.SetAcc(textBox1.Text);
}
Code from Form 2
public Generated()
{
InitializeComponent();
textBox1.Text = Data.GetAcc();
}
Now if I send a second value it should be displayed in the textbox in the next line and the first value should be in the first line.

Well, the general approach would be to use properties on the second form and set them in the calling form.
You seem to be using some kind of data holder that keeps all the data entered by the user. This is also a valid approach, but the way you
implement it doesn't fit what you describe.
If you want to keep several values you either need to use several properties or (in your case) a list of entries. Maybe this could be a better approach in your case:
Code from data.cs
private static List<string> Acc = new List<string>();
public static string[] GetAccounts()
{
return Acc.ToArray();
}
public static void AddAccount(string value)
{
Acc.Add(value)
}
Code from Form 1
private void bunifuThinButton21_Click(object sender, EventArgs e)
{
Data.AddAccount(textBox1.Text);
}
Code from Form 2
public Generated()
{
InitializeComponent();
textBox1.Text = String.Join(Environment.NewLine, Data.GetAccounts());
}

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.

Repopulate a form field from a different class in C#

I'm trying to repopulate a textbox from a separate class. I've looked through a number of instances of this same question and found what I thought was a good solution. But, I can't make it work. I've tried to resolve the issue by creating a separate thread to send the data back. I don't know if this is a great idea or not. But, I know the data is getting back to the correct place without it because it shows up in the console. Any suggestions? Thanks!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void updater(double value)
{
textBox1.Text = value.ToString(); // Trying to update here
Console.WriteLine(value); // The new multiple makes if back to here...
}
private void button1_Click(object sender, EventArgs e)
{
CALC c = new CALC();
c.valuecalculator(.0025);
}
}
public class CALC
{
public void valuecalculator(double multiplier)
{
for (int index = 0; index < 1000; index++)
{
Form1 f = new Form1();
double newMultiple = index * multiplier;
f.updater(newMultiple);
}
}
}
You're making a new copy of the form in your valuecalculator method, but you should be using the same form.
There are loads of ways to solve this.
You could pass an instance of the form into your valuecalculator method.
You could make the reference to the form static in your Program.cs or whatever startup file originally initialises it.
You could give the form a reference to itself
You could put the code to update the form in the button1 click event (this makes most sense) by making the valuecalculator return the result instead of returning void
Your components should only do one thing. The calculator should perform a calculation and return the result:
public static class Calc
{
public static double CalculateValue(double multiplier)
{
return 100 * multiplier;
}
}
Forms should be as simple as possible. Meaning they are only concerned with displaying form elements and passing events to event handlers. The actual logic that happens in these event handlers should be someone else's responsibility. I like to pass this logic in the constructor:
public partial class Form1 : Form
{
public Form1(Func<double, double>CalculateValue)
{
InitializeComponent();
button1.Click += (sender, eventArgs) => textBox1.Text = CalculateValue(.0025).ToString();
}
}
Constructing and connecting classes with each other is another responsibility. The simplest version is to use your Main() method:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form1(Calc.CalculateValue);
Application.Run(form);
}
}

passing value from another class to textbox in form?

I have a class and a form. the class is intended to do some processes when event is raised and return back the values to the form to display only. I kind of have problem passing values back to form. For instance, I have this code in class print:
public class PrintClass : Form1
{
public void printEventHandler(object sender, EventArgs e)
{
string text = "Process Completed";
append_Tbox(text);
}
}
and the method in form1 to display the text:
public void append_Tbox(string s)
{
TboxPrint.AppendText(s);
}
However, nothing is displayed. I believe there is something wrong, but I can't figure it out.
What is the fastest way to pass values from the class to form?
First off, your processing class shouldn't extend Form1. This is giving you the illusion that you can access the methods of your existing form, but it's not doing what you think it is. You're creating an entirely new form when you do this, and just not showing it. That form has it's own set of all instance fields, so you're not accessing the controls of your main form. Even if this would work (and it won't) it's not a well designed solution.
The proper way to do this is actually much easier. You just need to have your other class return a value from it's method:
public class PrintClass
{
public string DoWork()
{
Thread.Sleep(2000);//placeholder for real work.
return "Process Completed";
}
}
Now your main form can just call that method and append the return value to a textbox.
Once you do this you'll have an entirely separate issue. If you do the work in the UI thread you'll be blocking that UI thread while the work takes place, preventing the form from being repainted, or any other events from being handled. You need to do the work in a background thread and then marshal back to the UI thread to update the UI with the results. There are a number of ways of doing this, but if you have C# 5.0 using await is by far the easiest:
public class Form1 : Form
{
private void SomeEventHandler(object sender, EventArgs args)
{
string result = await Task.Run(()=>new PrintClass().DoWork());
TboxPrint.AppendText(result);
}
}
If you need a C# 4.0 solution you can use ContinueWith, which is more or less what the above will be translated to, but it's not quite as clean of syntax.
public class Form1 : Form
{
private void SomeEventHandler(object sender, EventArgs args)
{
Task.Factory.StartNew(()=>new PrintClass().DoWork())
.ContinueWith(t => TboxPrint.AppendText(t.Result)
, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
}
I have create delegate in Main Form
public delegate void LoginDelegate(string s);
public partial class AirLineReservationMDI : Form
{
LoginDelegate loginAirLineDelegate;
}
loginAirLineDelegate = new LoginDelegate(DisableToolStripMenuItems);
public void DisableToolStripMenuItems(string s)
{
this.viewToolStripMenuItem.Visible = true;
this.bookingToolStripMenuItem.Visible = true;
this.existingUserToolStripMenuItem.Visible = false;
this.newUserToolStripMenuItem.Visible = false;
this.toolStripStatusUserID.Text = "USerID :- "+s;
this.LoginUserId = s;
}
in Another Class, (I have passed delagete object to this class )
I fired the Delegate
logDelegate(textBoxUserName.Text);
I used Action<T> delegate to solve the problem. here is the code and it works fine.
class PrintClass
{
public Action<string> DisplayDelegate;
public void printEventHandler(object sender, EventArgs e)
{
string text = "Event Handled, and text value is passed";
var copy = DisplayDelegate;
if (copy != null)
{
copy(text);
}
}
}
and in `Form1.cs' :
private void Form1_Load(object sender, EventArgs e)
{
PrintClass p = new PrintClass();
BtnPrint.Click += p.printEventHandler;
//subscrite the displayevent method to action delegate
p.DisplayDelegate += DisplayEvent;
}
public void DisplayEvent(string s)
{
Invoke(new Action(() => TboxPrint.AppendText(s)));
}
so the text 'Event Handled, and text value is passed' is displayed on the textbox.
I m not sure if it is the efficient way.
Thanks guys.

How to get a list box to disallow duplicate items?

Bassicly im creating a program that reads information from an xml file into a lisbox and allows the user to transfer items in the list box to another listBox.
But i want to some how disallow multiple items from being imported from one listBox to the other. I thought i can somehow do an experession to check if the String already Exists in the listBox.
The reason i want to do this is because the user can click x amount of times in order to import items and it's unproffesional.
Any Help would be appreciated thank you.
private void button1_Click(object sender, EventArgs e)
{
if (!listBox.Items.Exists) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.Items[listBox1.SelectedIndex]);
}
}
private void button1_Click(object sender, EventArgs e)
{
if (!listBox.Items.Exists) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.Items[listBox1.SelectedIndex]);
}
}
That will work actually, but you need to use the Contains method. However, you may be missing one crucial point.
What type of items are you using to populate your ListBox? Exists will call .Equals which, by default, uses reference equality. So, if you need to filter based on value, you need to override .Equals for your type and change the semantics.
For example:
class Foo
{
public string Name { get; set; }
public Foo(string name)
{
Name = name;
}
}
class Program
{
static void Main( string[] args )
{
var x = new Foo("ed");
var y = new Foo("ed");
Console.WriteLine(x.Equals(y)); // prints "False"
}
}
However, if we override .Equals to provide value type semantics...
class Foo
{
public string Name { get; set; }
public Foo(string name)
{
Name = name;
}
public override bool Equals(object obj)
{
// error and type checking go here!
return ((Foo)obj).Name == this.Name;
}
// should override GetHashCode as well
}
class Program
{
static void Main( string[] args )
{
var x = new Foo("ed");
var y = new Foo("ed");
Console.WriteLine(x.Equals(y)); // prints "True"
Console.Read();
}
}
And now your call to if(!listBox.Items.Contains(item)) will work as you intended it to. However, if you wish it to continue working you will need to add the item to both listboxes, not just listBox2.
This should do it for you...
private void button1_Click(object sender, EventArgs e)
{
if (!ListBox.Items.Contains(listBox1.SelectedItem)) // Random Idea which doesnt work
{
listBox2.Items.Add(listBox1.SelectedItem);
}
}

returning value to main C#

I'll start by saying that i am no beginner in C# but not very much more and need help returning value to main. Or rather tell me what is the "correct" way.
I want to return a fail value (simply -1) from the application, in case of any exception and ending up in a catch. In that case passing info to main to return -1.
The way I solved it was by just adding a static global variable mainReturnValue (to be able to access it from main), and setting its value to -1 in the catches.
Is that a correct way of doing it, based on my current code?
If anyone is wondering the applications is executed without user interaction and that's why I need to catch the exit state. The form/GUI just displays info about the progress, in case it's started manually.
namespace ApplicationName
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{ ...
static int mainReturnValue = 0; //the return var
static int Main(string[] args)
{
Application.Run(new Form1(args));
return mainReturnValue; //returning 0 or -1 before exit
}
private void Form1_Load(object sender, System.EventArgs e)
{
the code..in turn also calling some sub functions such as DoExportData...and I want to be able to return the value to main from any function...
}
private int DoExportData(DataRow dr, string cmdText)
{
try { ... }
catch
{ mainReturnValue = -1; }
}
Thanks.
You could do this:
static int Main(string[] args)
{
Form1 form1 = new Form1(args);
Application.Run(form1);
return form1.Result;
}
and then define a property on your Form1 class, whose value you can set after the DoExportData method executes. For example:
public int Result { get; private set; }
private void Form1_Load(object sender, System.EventArgs e)
{
Result = DoExportData(...);
}
private int DoExportData(DataRow dr, string cmdText)
{
try
{
...
return 0;
}
catch
{
return -1;
}
}
How to: Get and Set the Application Exit Code from MSDN.
By the way, an exit code of 0 indicates success, while anything > 0 indicates an error.
I would add also something like this
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
static void CrashHandler(object sender, UnhandledExceptionEventArgs args) {
mainReturnValue = -1;
}
Just to be sure that even unhandled exceptions are "handled" by your application in a way you want, cause I presume your app is not only about one WindowsForm.

Categories

Resources