So I have a small project I am working on. Basically what I want to do is create another class, with the SQL connection as well as the results. However, it is telling me:
The Name 'firstName' does not exist.
When I put it on the page that is created for the designer mode in visual studio, it goes away and works.
info.cs:
public void GetInfo(string accountNumber)
{
string source = helper.CnnVal("WorkflowConfiguration");
SqlConnection con = new SqlConnection(source);
con.Open();
string sqlSelectQuery = $"Select TOP 1 * From [Workflow Creation].[dbo].[ssFields] Where Field16 =" + int.Parse(accountNumber);
SqlCommand cmd = new SqlCommand(sqlSelectQuery, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
firstName.Text = (dr["Field1"].ToString());
lastName.Text = (dr["Field2"].ToString());
dateOfbirth.Text = (dr["Field3"].ToString());
socialSecurity.Text = (dr["Field4"].ToString());
}
con.Close();
}
I would like to make a reference to the "designer" code page. So I can reference the results in the btn click below:
namespace WindowsFormsApp1
{
public partial class dataBase : Form
{
List<Information> people = new List<Information>();
private personalInfo personal = new personalInfo();
public dataBase()
{
InitializeComponent();
}
public void searchBtn_Click(object sender, EventArgs e)
{
dataAccess db = new dataAccess();
people = db.GetPeople(accountNumber.Text);
ListBoxPeople.DataSource = people;
ListBoxPeople.DisplayMember = "FullInfo";
//Would like to references here from info.cs
}
You seem to be dealing with Windows Forms here, as your main class is a Form. To start things off, I would like to recommend against giving Forms names that are completely unrelated to them. I have the habit of naming the main forms of my applications MainForm, but you could also use, for example, MyAppForm (the name of your application plus the word Form).
Setting that aside, if you need to access a control on your form (such as a TextBox), I recommend that you do so within the Form class itself, unless you have an excellent reason to do so. You will not be able to reference things from outside the form class (as controls are Private), and even if you write a method to pull the controls from your Form, you won't be able to access them (they will be on a different thread), unless you implement an algorithm to get around that.
Therefore, I suggest that you move your GetInfo method to your form class. Notice that that class is a partial class, that means you can create a new class file with the same class name and it will extend your form class, better organizing things (this is what Designer code generation does, hence why you're not supposed to alter things on the Designer file).
Edit: Additionally, as suggested above, if the context of your form doesn't suit your method, you can also pass the data required by a control via an extra public acessible method. That extra method can be called by your Form event, for example.
Note: Be sure to define the class as partial on the other file as well, if you intend to do this.
Related
I am working on a Winforms application that uses base window (e.g. Form1) and many other windows (e.g. Form2, Form3, ...). All of these windows have their property TopLevel set to false, no border and I am placing them in the Form1 when I need them. I am not skilled enough or do not have the brain capacity to solve this issue:
public void ShowForm(string strNewForm) {
var frmNew = Activator.CreateInstance(Type.GetType(strNewForm)) as Form;
frmNew.TopLevel = false;
frmNew.Size = new Size(rctForm.Width, rctForm.Height);
frmNew.Location = new Point(rctForm.X, rctForm.Y);
frmNew.InitializeForm(strActualSection, strActualSubSection);
frmNew.Parent = this;
frmNew.Show();
}
The strNewForm variable contains the name of Form to show. All the methods and properties in each Form can be used as these all are inherited from base class Form. Problem is with InitializeForm() which I use in each form (Form2, Form3, ...) to do various stuff. I know my problem is in this line:
var frmNew = Activator.CreateInstance(Type.GetType(strNewForm)) as Form;
When strNewForm contains string "Form2" and I change as Form to as Form2 it works just fine. I know I need to change it to proper name each time, but I don't know how. I tried to use this:
Type frmType = Type.GetType(strNewForm);
var frmNew = Activator.CreateInstance(Type.GetType(strNewForm)) as frmType;
But it throws an error CS0118: frmType is a variable but is used as a type. I don't know how to solve this, I tried many solutions and I googled for half a day straight and I am still lost. Any insight would be really helpful.
You cannot use a run-time variable to create strongly-typed code.
You have to provide a compile-time type after the as.
If you know it's a Form then all you can do is this:
var frmNew = Activator.CreateInstance(Type.GetType(strNewForm)) as Form;
If you need specific methods or properties then use a custom Form as your base-type and use that in the as.
Why won't you pass a Form object in your ShowForm method?
public void ShowForm(Form newForm)
{
newForm.TopLevel = false;
newForm.Size = new Size(rctForm.Width, rctForm.Height);
newForm.Location = new Point(rctForm.X, rctForm.Y);
newForm.InitializeForm(strActualSection, strActualSubSection);
newForm.Parent = this;
newForm.ShowDialog();
}
I am try to retrieve the data from my table which I created on my SSMS. I created a list box in a form of visual studio, and I try to display the data from database, but it doesn't send anything when I try to load up the program. The database is seems to look good. That problem appear when I try to retrieve the movie_id and movie_title.
Here is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DataBase
{
public partial class Form1 : Form
{
DataTable dt = new DataTable();
public void LoadData()
{
SqlConnection conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;"+
"Initial Catalog=online_tv;Integrated Security=SSPI;");
SqlCommand cmd = new SqlCommand("SELECT movie.* FROM movie", conn);
SqlDataAdapter sa = new SqlDataAdapter(cmd);
conn.Open();
sa.Fill(dt);
conn.Close();
sa.Dispose();
cmd.Dispose();
conn.Dispose();
}
public class MyMovie
{
public int id;
public string title;
public override string ToString()
{
return title;
}
}
public void ShowMovies()
{
int i;
for (i = 0; i < dt.Rows.Count; i++)
{
MyMovie movie = new MyMovie();
movie.id = Convert.ToInt32(dt.Rows[i]["movie_id"]);
movie.title = Convert.ToString(dt.Rows[i]["movie_title"]);
listBox1.Items.Add(movie);
}
}
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
LoadData();
ShowMovies();
}
There are a bucketload of optimizations to be made here, but I'd like to post an answer that introduces a small but fundamental change that will make your life significantly easier. Nearly every single line of code you've written there, you can get Visual Studio to write for you; just like you get it to write code when you lay out a Form, you can have it do all of this data access stuff too, and if you've managed to get SSMS connected, then getting VS connected is virtually the same process and will mean it just works:
Add a DataSet type of file to your project, and open it
Right click on it and choose add a TableAdapter - this is like a DataAdapter on steroids
Add a new conenction - the dialog is virtually the same as SSMS so you should be able to connect your DB without any hassle
Say you want to write "a query that returns rows" - put SELECT * FROM movie in
Finish the wizard
Right click the "Fill" line in the tableadapter and choose Preview Data, hit the button and see your data. If you see no data, you connected to a database that is devoid of data
Go to your form, open the Data Sources window (View menu.. Other Windows)
Drag the movie node out of the Data Sources window and onto the form
Run the app
You'll see your data
Now that you've scratched the surface of this, you can start playing with other stuff. Throw the DataTable dt away; you won't need it. Your form has a dataset object on it, that contains a Movie property that is a MovieDataTable - a subclass of datatable that you can access in a more logical and modern manner than via "string column names" - you say, for example, yourdatasetnamehere.Movies[0].movie_title and it's already a string (time to swap your column names to PascalCase by the way) rather than somedatatable.Rows[0]["movie_title"].ToString()
To show your movies in a listbox,
add a listbox to the form
set the DataSource property to be the movieBindingSource
Set the DisplayMember to be movie_title
(All this is done visually on the forms designer, not in code)
You can consider throwing the Movie POCO away too; a MovieDataRow is created by the dataset generator; it has all the properties of your movie, in a strongly typed fashion, just like your POCO does. The tableadapter downloads the DB data and turns it into strongly typed MovieDataRow objects for you, meaning you can throw all the POCO mapping stuff in ShowMovies away too, and finally, databinding your listbox means you can toss out the bit where you build its items collection manually.
I have a small design question which I couldn't find relevant google hits for some reason.
I have a user control which I use in my application.
The main form opens a second form as a dialog. T
his second form is using the user control which includes a list box.
Naturally I want to preserve the list box items when the forms dispose so I am keeping a private list in the main form.
List<string> _listofFirstCoordinates = new List<string>();
Now the question is, should the dialog form be the one responsible for relaying the list to the main form or should the code be in the user control?
Should the one populating the list be the user control
lst_Coordinates.Items.AddRange(ListOfCoordinates.Cast<object>().ToArray());
or should the form using it populate it (The subform)
uc_EditCoordinates.ListOfCoordinates = ListOfCoordinates;
Also is it feasible to just have the user control be a public variable for the form holding it so it may be changed directly or would that be bad design?
Edit:
By the way, the data is saved for now in variables going back and forth between the forms as the user has to finish all subforms before submitting and finally saving it to the database. So it is a
var _listofFirstCoordinates = new List<string>();
going back and forth.
The "correct" solution is to abstract-away the View-level concern (in this case, anything to do with Form, UserControl, and UI controls) away from the Controller and Model-level concerns (in this case, your application's data).
Without completely rearchitecturing your system, you can still apply this separation-of-concerns within your example.
You can conceptually argue the "code-behind" of your MainForm class acts as a kind of Controller (purists would disagree). It will have to know about creating the child form, but it does not need to know about the user-control hosted within the child form - that would be the concern of the child form's.
I suggest defining a class that represents a ViewModel - albeit as we're using WinForms we will use it as a kind of crude "one-way" ViewModel, like so:
class MainForm : Form {
private void ShowChildFormModal() {
ChildViewModel vm = new ChildViewModel();
vm.CoordinatesList = ...
vm.OtherData = ...
ChildForm child = new ChildForm();
child.LoadFromViewModel( vm );
child.ShowDialog();
child.SaveToViewModel( vm );
SaveToDatabase( vm );
}
}
class ChildViewModel { // this is a POCO
public List<String> CoordinatesList;
public Int32 OtherData;
}
class ChildForm : Form {
public void LoadFromViewModel(ChildViewModel vm) {
// save time and trouble by using the List as a datasource directly, or you can manually populate the combobox as well
this.childUserControl.LoadFromViewModel( vm );
this.someOtherControl.Value = vm.OtherData;
}
public void SaveToViewModel(ChildViewModel vm) {
// completing this is an exercise for the reader
// but basically copy values from the controls on the form into the `vm` instance
}
}
class ChildUserControl : UserControl {
public void LoadFromViewModel(ChildViewModel vm) {
this.comboBox.DataSource = vm.CoordinatesList;
}
}
I have been working with Entity Framework (VS2010 Framework 4.0) in my proyect. I had some trouble with using a different object context per form. What I did then, was to create a object context in the Main Menu Form (stays opened) and everytime I create and show one form, I pass that object context to this new form. Example:
public partial class frm_Menu : Base
{
public Sistema_financiero_Entities db = new Sistema_financiero_Entities();
private void cancelarCuotaToolStripMenuItem_Click(object sender, EventArgs e)
{
frm_Cancelacion_Cuota Form1 = new frm_Cancelacion_Cuota();
Form1.db = db;
Form1.Show();
}
}
Ok, that solution worked fine until now because I needed to use and pass objects throw the differents forms sometimes, and if the objects contexts were different, I got an error.
Now, I have detected a huge issue using it this way. I have a form, where I can pay for the different installments of a loan. I´ll attach an image so then you can see what I´m talking about.
There, you select the different installments you want to pay for. Then, you introduce the value you will finally pay in "Total cobrado". Here is the important thing: When the checkbox image is checked (the blue one - already checked in the image), I create a "payment" entity per installment. Every "payment" object is stored in a list. If I uncheck it, I can change the value and the same thing is done. Obviously, I´m clearing the list before doing a list.Clear();. Then, one the checkbox checked, I can press "Aceptar" (accept). There I add to the database every "payment"(PAGO) in the list. After that, I save all changes.
foreach (Pago p in Lista_nuevos_pagos)
{
db.AddToPago(p);
}
try
{
db.SaveChanges();
this.Close();
}
My problem, is that it´s not only adding those "payments" in the list but the other "payments" entities that were in the list before clearing it. I reach the conclusion that when I clear the list, the objects remains in the object context. I thought that if the entity is not in the database, I have to Add it to the entity in the object context as I did with pago (db.AddToPago(p);).
I wanted to ask you guys how can I solve this issues. I solved it now doing this:
private void cancelarCuotaToolStripMenuItem_Click(object sender, EventArgs e)
{
Sistema_financiero_Entities db = new Sistema_financiero_Entities();
frm_Cancelacion_Cuota Form1 = new frm_Cancelacion_Cuota();
Form1.db = db;
Form1.Show();
}
Instead of creating just one global db for all forms, I create one in the Main Menu for every form. Then, in that form closed event, I dispose that object context.
Then, when i check the checkbox image, before creating the "payments", I delete every "Pago" entity from the object context:
foreach (Pago p in Lista_nuevos_pagos)
{
db.DeleteObject(p);
}
Lista_nuevos_pagos.Clear();
Doing this works correctly, but I´m still having trouble with some other created entities (Installments) that are not deleted when I clear a list. I think I´m doing it wrongly, thats why I need some direction to use EF correctly. I really need to get this done really soon, I don´t have too much time to read EF tutorials.
Just in case, this is how I create every "Pago" (payment)
Pago p = new Pago();
p.desc_aumento_intereses = nudwb1.Value;
p.desc_aumento_punitorios = nudwb2.Value;
p.desc_aumento_gastos = nudwb3.Value;
p.desc_aumento_comision = nudwb4.Value;
p.cotizacion = ntxt_Cotizacion.Value;
p.fecha_hora = fecha_hora;
Cuota c = new Cuota();
string name = tbx.Name.Substring(tbx.Name.IndexOf("-") + 1);
int nro_cuota = Convert.ToInt32(name);
c = Lista_cuotas_cobrar.Where(x => x.num_cuota == nro_cuota).First();
p.Cuota.Add(c);
Thank you for reading, I know this is a lot of info. Hope some guide soon..
I guess that you have references to those object in your Lista_nuevos_pagos list. This is why they will be duplicated.
I'm creating a sql statement in c#, and I am trying to get the value from a text box in a previous form:
SqlParameter PeriodFrom = new SqlParameter("#PeriodFrom", SqlDbType.VarChar);
PeriodFrom.Value =
I am just unsure of what goes after the equals sign. I tried the form name.textbox name.
In the code behind of the form, inside the form class, you can declare a property:
public string TextBoxValue
{
get
{
return textBoxName.Text;
}
}
And you can use it with your SqlParameter like this:
SqlParameter PeriodFrom = new SqlParameter("#PeriodFrom", SqlDbType.VarChar);
PeriodFrom.Value = FormClassName.TextBoxValue;
Edit:
This wouldn't work since the Form class object is not static and it wouldn't persist. To make this work, you would need to make changes to the Program class. You would need to add a static Data member in the Program class like this:
public static FormClassName form;
and would need to pass this in the main method as below:
form = new FormClassName();
Application.Run(form);
And in the SQLParameter you can pass it like this:
SqlParameter PeriodFrom = new SqlParameter("#PeriodFrom", SqlDbType.VarChar);
PeriodFrom.Value = Program.form.TextBoxValue;
I tried to give you one of the ways to get the value but I do not think this is a good practice. Ideally, for passing values between forms, or layers you need to have some mechanism for storing and retrieving values, like a context, or Session. This is not the solution but a work around. And I take no responsibility if the code gets messed up cause of the above changes. :)
If your TextBox is publicly declared on your form, then you will be able to access its properties from the scope with which it was created in.
PeriodFrom.Value = otherForm.TextBoxName.Text;
If the 'previous' form object is not available to you now, then you will have to retrieve the value and pass it in as a parameter into your new form (or something of the sorts). Please supply more code/details if you want help here.
Change your textbox's modifier property to Public
then
formname.textboxname.Text
<%# PreviousPageType VirtualPath="~/SourcePage.aspx" %>
if(PreviousPage != null)
{
if(PreviousPage.IsCrossPagePostBack == true)
{
PeriodFrom.Value =PrevForm.TextBox.Text;
}
}
else
{
PeriodFrom.Value = "Not a cross-page post.";
}
YourPreviousForm.YourTextBox.Text
Get the value of textbox by using Text property of TextBox.
PeriodFrom.Value =PrevForm.TextBox.Text;
As you are saying that there is no accessbile due to protection level, you need to work on the access modifier of form from protected to public so that it can be accessible.