hello guys i have a form... and i set my properties if the user will click the submit button and after then i will call my add_data function which contains my database query...but the problem is the properties I've set in my form will become empty in my add_data function...why this is happening?
actually i already try adding a messagebox in my form which contains the data in my properties after setting my properties value and it works fine but when i add it to my databasecon class the messagebox shows null... i try also putting my properties and database query function in the same class and it's working but what i want is to separate my properties and my database query functions...
this is the codes in my properties
class persons
{
//person attributes
private string fname;
private string lname;
private string age;
private string gnder;
private string address;
//initialize
public persons()
{
this.fname = "";
this.lname = "";
this.age = "";
this.gnder = "";
this.address = "";
}
//set and get properties
public string p_fname
{
get { return this.fname; }
set { this.fname = value; }
}
public string p_lname
{
get { return this.lname; }
set { this.lname = value; }
}
public string p_age
{
get { return this.age; }
set { this.age = value; }
}
public string p_gender
{
get { return this.gnder; }
set { this.gnder = value; }
}
public string p_address
{
get { return this.address; }
set { this.address = value; }
}
}
this is the codes in my form
public partial class add : Form
{
persons p = new persons();
databasecon d = new databasecon();
private void addbtn_Click(object sender, EventArgs e)
{
p.p_fname = this.fname.Text;
p.p_lname = this.lname.Text;
p.p_age = this.age.Text;
p.p_gender = this.gender.Text;
p.p_address = this.address.Text;
d.add_data();
this.Close();
}
}
and this is the codes in my database connection and queries
class databasecon
{
OleDbConnection con = new OleDbConnection();
persons p = new persons();
public databasecon()
{
con.ConnectionString = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=../dbsample.mdb";
}
public void add_data()
{
try
{
con.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO person(u_fname,u_lname,u_age,u_gender,u_address)VALUES('" + p.p_fname + "','" + p.p_lname + "','" + p.p_age + "','" + p.p_gender + "','" + p.p_address + "')";
cmd.Parameters.AddWithValue("u_fname", p.p_fname);
cmd.Parameters.AddWithValue("u_lname", p.p_lname);
cmd.Parameters.AddWithValue("u_age", p.p_age);
cmd.Parameters.AddWithValue("u_gender", p.p_gender);
cmd.Parameters.AddWithValue("u_address", p.p_address);
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
MessageBox.Show("Error : " + e);
}
finally
{
con.Close();
MessageBox.Show("New person has been successfully added.");
}
}
}
You need to pass p as a parameter to the add_data method.
public void add_data(persons person)
then call it with the parameter:
d.add_data(p);
and use the properties of person in the method:
cmd.Parameters.AddWithValue("u_fname", person.p_fname);
cmd.Parameters.AddWithValue("u_lname", person.p_lname);
cmd.Parameters.AddWithValue("u_age", person.p_age);
cmd.Parameters.AddWithValue("u_gender", person.p_gender);
cmd.Parameters.AddWithValue("u_address", person.p_address);
you create databasecon() in form and then call add_data method and you don't pass 'persons' instance. in databasecon you use persons istnace which is field in this class. you soudl add parameter do add_data method and pass instance or 'persons' you want to save and use it in command
Your p fields in your add and databasecon classes are separate. When you call d.add_data(), the d object can only see its instance of persons p ....
To fix this, pass the persons object into the add_data method.
class databasecon{
// Remove this line, we pass it into the function below
/* persons p = new persons(); */
public void add_data(persons p){
try{
// same code as before
}catch(Exception e){
// same code
}
finally{
// same
}
}
}
You have an instance of Person class which you fill and then use an instance of databasecon which is completely not conntected to the person class you filled.
Change add_data() to
public void add_data(person p) { ... }
this will use the properties from p passed as parameter.
You call it like this
d.add_data(p);
Except for that have a look at some C# for begginers book.
Overlooking the fact that your code is extremely poorly written.
You are not passing in the persons class that you created.
Something like
public void add_data(persons p) {//..blah}
Then
private void addbtn_Click(object sender, EventArgs e) {
p.p_fname = this.fname.Text;
p.p_lname = this.lname.Text;
p.p_age = this.age.Text;
p.p_gender = this.gender.Text;
p.p_address = this.address.Text;
d.add_data(p);
this.Close();
}
From what I can see in the code above, you call add_data from your databasecon class, which has an instance p of Person. Since you are not passing a Person object to your add_data method, the empty, unset p object is what is being saved to the database.
Adding a Person parameter to add_data and use that when saving the data to the database.
There are several things I don't like in your code.
Let's start however with your specific problem:
Your code contains also a source of security issues and malignous SQL code injection.
You are saving always an empty person and there is a problem with your SQL connection string.
Try this code instead.
private void addbtn_Click(object sender, EventArgs e)
{
try
{
persons p = new persons(); // we use a new instance of person class
p.p_fname = this.fname.Text;
p.p_lname = this.lname.Text;
p.p_age = this.age.Text;
p.p_gender = this.gender.Text;
p.p_address = this.address.Text;
d.add_data(p); // we save the instance of persons
this.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error : " + e);
}
}
...
class databasecon
{
public void add_data(person p) // we need a person as parameter
{
OleDbConnection con = new OleDbConnection();
con.ConnectionString = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=../dbsample.mdb";
con.Open();
try
{
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
// this is the correct sql command string
cmd.CommandText = "INSERT INTO person(u_fname,u_lname,u_age,u_gender,u_address) " +
VALUES (#u_fname, #u_lname, #u_age, #u_gender, #u_address)";
cmd.Parameters.AddWithValue("u_fname", p.p_fname);
cmd.Parameters.AddWithValue("u_lname", p.p_lname);
cmd.Parameters.AddWithValue("u_age", p.p_age);
cmd.Parameters.AddWithValue("u_gender", p.p_gender);
cmd.Parameters.AddWithValue("u_address", p.p_address);
cmd.ExecuteNonQuery();
}
finally
{
con.Close();
}
}
...
}
Now let's talk about code style.
Is a good thing to use CamelCase style in your code, look on the web about C# CamelCase:
Classes and properties should all start with a capitalized letter.
Your class express a single person not a list of persons so its name should be public class Person.
Avoid the use achronims or of short names when you can...
p_lname should be LastName, people will thanks you if you make your code more readable, C# is not C and C# is not PHP!
A field or a property with a longer name will not consume more memory than a property with a short and unreadable name :)
Use always strong typing... age is not a string, age is an integer.
The property should be public int Age, not a string!
Never use MessageBox in your non-visual classes.
Try to catch for exceptions in your client code, not in your library code!
I dont know if I 100% understand the issue about I guess it's because your inserting an empty persons class into the db.
Your `add_data method should take a person object like so.
public void add_data(persons obj)
{
p = obj;
you must pass person object to add_data method
public void add_data(persons p)
{
...
}
and call it:
d.add_data(p);
Related
I am getting phone contacts into a list<> and saving it in a database.
Below is my code.
This is my method to get the contacts-List
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
try {
SetContentView(Resource.Layout.Main);
TextView txtcount = this.FindViewById<TextView>(Resource.Id.textView1);
List<PersonContact> a1 = GetPhoneContacts();
Phone gp = new Phone();
gp.insertContact(a1);
} catch (System.Exception ex) {
alert(ex.Message);
}
}
Via the following method I am trying to store contacts in database
[WebMethod]
public string insertContact<T>(List<PersonContact> a) {
OpenConnection();
if (a.Count > 0) {
for (int i = 0; i < a.Count; i++) {
string str = "insert into phone_contact (FirstName,LastName,PhoneNumber)values('" + a[i].FirstName + "','" + a[i].LastName + "','" + a[i].PhoneNumber + "')";
SqlCommand cmd = new SqlCommand(str, con);
cmd.ExecuteNonQuery();
}
return "1";
} else {
return "1";
}
}
public class PersonContact {
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}
I am getting an error while passing parameter
gp.insertContact(a1);
Your method is generic, as it introduces a new type parameter T. That's what the <T> at the end of the method name means.
However, you don't use T anywhere - so just make it a non-generic method:
public string InsertContact(List<PersonContact> a)
At the same time, I would very strongly urge you to change the way you're doing database access: it's currently vulnerable to SQL injection attacks. Instead, you should use parameterized SQL: have one parameter for each of FirstName, LastName and PhoneNumber.
You're also returning "1" regardless of the input. Your method could be written more simply as:
// Consider renaming to InsertContacts, as it's not just dealing with a single
// contact
public string InsertContact(List<PersonContact> contacts)
{
// You should almost certainly use a using statement here, to
// dispose of the connection afterwards
OpenConnection();
foreach (var contact in contacts)
{
// Insert the contact. Use a using statement for the SqlCommand too.
}
return "1";
}
That's assuming you need the value returned at all - if you're always returning the same value, why not just make it a void method?
ok guys/girls, i am new to programming and have a question. i created one winform for insert data into sql server..now i want to use that same form to update data..i already did that with constructor overload and chaining, and it is work!
on main form frmEmployees i have two buttons, btnAddEmployee and btnUpdateEmployee, i also have employeeID (i get id from the datagrid) and a bool variable called 'isEditMode =true', now when i click btnUpdateEmployee i am sending EmployeeID, and isEditMode values to overloaded constructor..and frmAddEmployee opens..there i have global private variabables employeeID and bool isEditmode..and then i set their values via overloaded constructor, and that is work, BUT..when i click btnAddEmployee i am not sending employeeID and isEditMode values..and i come up with unused variables when adding employee..
private int employeeID;
private bool isEditMode;
public frmAddEmployee()
{
InitializeComponent();
this.AutoValidate = AutoValidate.Disable;
}
public frmAddEmployee(int employeeID, bool isEditMode): this()
{
this.employeeID = employeeID;
this.isEditMode = isEditMode;
}
You haven't showed us a lot of code but i will give you good example of how i am handing communication between program and SQL Database.
So first of all I create class for each object. In your example i see you have Employee so i would create class with few information (variables) about each of my employee and functions i want to have for them. So class would look something like this:
public class Employee
{
static string databaseString = "";
public int Id { get { return _Id; } } //This is property
public string Name { get { return _Name; } set { _Name = value; } } //This is property
private int _Id; //This is private variable used by property
private string _Name; //This is private variable used by property
public Employee()
{
//Constructor used to create empty object
}
public Employee(int Id)
{
try
{
using (SqlConnection con = new SqlConnection(databaseString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT NAME FROM Employee WHERE ID = #ID", con))
{
cmd.Parameters.AddWithValue("#ID", Id);
SqlDataReader dr = cmd.ExecuteReader();
//I am usin IF(dr.Read()) instead of WHILE(dr.Read()) since i want to read only first row.
if (dr.Read())
{
this._Id = Id;
this._Name = dr[0].ToString();
}
else
{
System.Windows.Forms.MessageBox.Show("There was no Employee with that ID in database!");
}
}
}
}
catch(SqlException ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
public void Save(bool showMessage)
{
using (SqlConnection con = new SqlConnection(databaseString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("UPDATE Employee SET NAME = #N WHERE ID = #ID", con))
{
cmd.Parameters.AddWithValue("#N", this._Name);
cmd.Parameters.AddWithValue("#ID", this._Id);
cmd.ExecuteNonQuery();
if (showMessage)
System.Windows.Forms.MessageBox.Show("Employee saved!");
}
}
}
public static void Create(string Name, bool showMessage = true)
{
using (SqlConnection con = new SqlConnection(databaseString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("INSERT INTO Employee (ID, NAME) VALUES (COALESCE(MAX(ID), 1), #NAME)", con))
{
cmd.ExecuteNonQuery();
if (showMessage)
System.Windows.Forms.MessageBox.Show("New Employee created!");
}
}
}
}
Now when i have my class i can call it 2 ways:
Employee emp = new Employee(); //This will create empty employee object
Employee emp1 = new Employee(1); //This will create employee object and will load employees data from database where employees id == 1
Also what i can do is:
Employee.Create("SomeName"); //Calling public static method from Employee class. Doesn't require you to create object for static methods
or if i have loaded employee and want to change it's name and then save i would do it like this:
Employee emp2 = new Employee(1); //Created and loaded emp from database
emp2.Name = "Changed Name";
emp2.Save(); //Called public method.
So now if you have form which display one employee it would look like this:
public partial class Form1 : Form
{
private Employee emp;
public Form(int EmployeeID)
{
InitializeComponents();
//Creating new object of Employee but with constructor that will automatically load variables into it.
emp = new Employee(EmployeeID);
//Checking to see if employee is loaded since if there was no employee with given ID it would return null
if(emp.Id == null || < 1)
{
DialogResult dr = MessageBox.Show("Employee doesn't exist. Do you want to create new one?", "Confirm", MessageBoxButtons.YesNo);
if(dr == DialogResult.No)
{
//User doesn't want to create new employee but since there is no employee loaded we close form
this.Close();
}
else
{
Employee.Create("New Employee");
MessageBox.Show("New employee created");
//Here we need to load this employee with code like emp = new Employee(newEmployeeId);
//To get new employee id you have 2 options. First is to create function inside Employee class that will Select MAX(ID) from Employee and return it. (bad solution)
//Second solution is to return value upon creating new employee so instead function `public static void Create()` you need to have `public static int Create()` so it returns newly created ID of new row in SQL database. I won't explain it since you are new and it will be too much information for now. You will easily improve code later. For now you can use Select Max(id) method
}
}
textBox1.Text = emp.Id;
textBox2.Text = emp.Name;
}
private void OnButton_Save_Click(object sender, EventArgs e)
{
DialogResult dr = MessageBox.Show("Do you really want to save changes?", "Save", MessageBoxButtons.YesNo);
if(dr == DialogResult.Yes)
{
emp.Save();
}
else
{
//Here create private Reload function inside form that will do emp = Employee(emp.Id) and then set UI again.
}
}
private void OnButton_CreateNewEmployee_Click(object sender, EventArgs e)
{
Employee.Create("New Employee");
int newEmpID = something; //As i said up create method to select MAX ID or update SQL inside Create function to return newly created ID
//I am using using since after form closes it automatically disposes it
using(Form1 f = new Form1(newEmpID))
{
f.showDialog()
}
this.Close();
}
}
Ok, I have 3 classes: Teacher, Student and Database for that matter. I wanna read data from database and put it in Teacher or Student. So i have to write something like this:
public Teacher dbSelect(string Table="Teacher")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}
But i must have this exact Method with Student return:
public Student dbSelect(string Table="Student")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}
Now I can write each one in their ViewModel, But I want to put them in Database class. So is there any way to do that?
(I know i can return them in a list and then work with that list, But just wanna know if there is a way or not!)
UPDATE:
I forgot to put dbConnect in here, so:
public List<Teacher> dbConnect(string query)
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
Teacher result = new Teacher(null, null, null, null, null, null, null, null);
// try
{
conn = new SQLiteConnection(db.db);
conn.Open();
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
}
// catch (Exception ex) { }
while (reader.Read())
{
Teacher temp = new Teacher(
reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString(),
reader[4].ToString(),
reader[5].ToString(),
reader[6].ToString(),
reader[7].ToString()
);
result.Items.Add(temp);
}
conn.Close();
return result.Items;
}
And again the exact thing exist for Student but returning:
public List<Student> dbConnect(string query)
{
...
}
Answer: I had a Base class and of course wanted to return a List with a specific type, So I used #Jauch answer, but with returning the List.
Here is an idea on how to do what you want, adapted from a code of mine:
public class BaseClass<T>
where T : new ()
{
protected List<object> list;
protected string query;
protected PropertyInfo[] fProperties;
protected Assembly fStoreAssembly;
public BaseClass()
{
list = new List<T>();
fStoreAssembly = Assembly.GetAssembly (typeof(T));
fProperties = typeof(T).GetProperties();
}
public void Read()
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
try
{
conn = new SQLiteConnection(db.db);
conn.Open();
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
StoreResults (reader);
conn.Close();
}
catch (Exception ex)
{
//deal with the exception here
}
}
//Store results walks through all the records returned and
//creates new instances of the store object and saves in the list,
//using reflection
protected void StoreResults (SQLiteDataReader reader)
{
if (fProperties == null)
throw new Exception ("Store type definition is missing");
while (reader.Read ())
{
object newStoreItem = fStoreAssembly.CreateInstance (typeof(T).FullName);
foreach (PropertyInfo pi in fProperties)
{
string lcName = pi.Name.ToLower ();
if (HasColumn(reader, lcName))
{
if (!reader.IsDBNull(reader.GetOrdinal(lcName)))
pi.SetValue(newStoreItem, reader[lcName], null);
}
}
list.Add (newStoreItem);
}
}
public bool HasColumn (SQLiteDataReader reader, string columnName)
{
foreach (DataRow row in reader.GetSchemaTable().Rows)
{
if (row ["ColumnName"].ToString () == columnName)
return true;
}
return false;
}
}
And here how you would create Teacher and Student
public class TeacherInfo
{
//Properties for store info from database
}
public class Teacher : BaseClass<TeacherInfo>
{
public Teacher ()
: BaseClass()
{
query = "whatever you want here"
}
}
public class StudentInfo
{
//Properties for store info from database
}
public class Student : BaseClass<StudentInfo>
{
public Student ()
: BaseClass()
{
query = "whatever you want here";
}
}
As the Read routine is public, you can call Read from any instance of Teacher or Student.
You can even create them and store as BaseClass and use it directly if you don't need to know if it is a student or a teacher (for common routines, etc)
This is not an extensive example, but just a point in the direction you could use to turn your code more generic.
You can follow the semantics of using interfaces to return the values and then cast the return type to an appropriate one, or use a base class (interfaces would be better, as you can still extend other classes as base classes while implementing the interface). The entity interface can be created as following,
public interface SchoolEntity {
// Provide the similar properties as members of this interface.
}
Then you can implement this interface in your Teacher and Student.
public class Student : SchoolEntity { }
public class Teacher : SchoolEntity { }
Finally, the parameter can be made a bit more clearer by using enumerations. They would be more clearer while reading, rather than having the same parameter types. Note that function overloading doesn't consider return type as a signature difference.
enum Entity { Teacher, Student }
And then you can check which data to return.
public SchoolEntity dbSelect(Entity type)
{
switch(type) {
case Teacher:
var query = "SELECT * FROM Teacher";
return dbConnect(query, true);
// Rest of the cases.
}
}
Note that, your SQL statement is open to SQL Injection and anyone can either drop the tables, or perform actions that can be passed to the engine.
Working in a list
Working with the list won't be a good idea. Afterall, what list would you return? Would that be, public List<Teacher> dbSelect or public List<Student> dbSelect? The answer and solution to this is to have a same type backing up these both types.
dbSelect function
Note that you are still returning only Teacher type, then why you are having a Student at all? You should definitely cast it back. As a matter of fact, if I had to develop this. I would have to the dbSelect function to take the Entity as a parameter to keep all of the database requests and processing in a single function.
public List<Teacher> dbConnect(Entity type)
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
Teacher result = null; // Can be set to null.
// try
{
conn = new SQLiteConnection(db.db);
conn.Open();
string query;
// This way, leave the function to build the query.
if(type == Entity.Teacher) {
query = "SELECT * FROM Teacher";
} else {
query = "SELECT * FROM Student";
}
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
}
// catch (Exception ex) { }
while (reader.Read())
{
if(type == Entity.Teacher) {
Teacher temp = new Teacher(
reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString(),
reader[4].ToString(),
reader[5].ToString(),
reader[6].ToString(),
reader[7].ToString()
);
result.Items.Add(temp);
} else {
// Add the student.
}
}
conn.Close();
return result;
}
Now in this code, you are aware result is of type Teacher. There was no list there and this made your code a bit confusing. Take my advice: Re-write the code.
Please also go through the following useful links:
Explicit Interface Implementation
https://en.wikipedia.org/wiki/SQL_injection
Signatures and overloading
I have a problem with calling a method void for a string.
I've created a class:
public string SendData(string val1){ return val1; }
public void RecoverBirth()
{
clsConnectionClass conn = new clsConnectionClass();
SqlCommand cmd = new SqlCommand();
SqlDataReader dr;
cmd.CommandText = "select * from birthday";
dr = cmd.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
SendData(dr[1].ToString() + " " + dr[2].ToString() + "\r\n");
}
}
}
}
And then I try to retrieve the data from the class
private void button_Click(object sender, EventArgs e)
{
var _test = new Test();
string Result = _test.RecoverBirth();
}
This error occurs:
Can't convert method "void" to "string"
I need RecoverBirth method to be Void not "string", because it has a lot of different cycle and not everything return something, and if I declare it as string I have to use a lot of return null.
Is there a (better) way to do this?
public class Test
{
public string StringValue { get; set;}
public void DoSome()
{
while(some code here)
{
//something here
//set StringValue to what you like
this.StringValue = "this is now the text";
}
}
}
and then
private void button_Click(object sender, EventArgs e)
{
var test = new Test();
test.DoSome();
var result = test.StringValue;
}
The void keyword in the C# language indicates that a method returns nothing.
You should use the return keyword which means that a method returns only one value. What type of return value of the method you should specify at signature of the method. For example:
public string MethodA(bool isItReally)
In the above code return value is type of string.
So, you should correct the method like that:
Your updated code:
class Test
{
public string RecoverBirth()
{
clsConnectionClass conn = new clsConnectionClass();
SqlCommand cmd = new SqlCommand();
SqlDataReader dr;
cmd.CommandText = "select * from birthday";
dr = cmd.ExecuteReader();
string colValue;
if (dr.HasRows)
{
while (dr.Read())
{
colValue= dr[1].ToString() + " " + dr[2].ToString() + "\r\n");
}
}
return colValue;
}
}
It is not possible to assign to a string variable a value of void method as
void method returns nothing.
You better start with basic ... It's very basic things in programming dude..
class Test
{
public string s1(string val) { return val; }
public string DoSome()
{
while(some code here)
{
s1(result1 + result2);
}
//Must return string to get as string
return someVariableOfString;
}
}
If you strictly want your method to be of void return type then pass parameter by reference with out keyword to the method, and in this case method can directly change the reference value and so you can get the new value back in 'calling' code.
You can learn more on out in MSDN
public void DoSome(out string result)
{
//Do whatever stuff you want and assign the new value(string in your case) to the parameter
result = "My new string after some processing.";
}
Calling:
string result;
DoSomething(out result); //After successful execution of this line `result` will have newly assigned string value from within the function
Hope this help you..
Ignoring all the nagging doubts about a design where something like this makes sense... you could use an argument to emit whatever output necessary. For example:
public void DoSomething(Action<string> someAction = null)
{
// When it's time to emit a result, just do
if (someAction != null) someAction("Hello world!");
}
Which you can then call as
var sb = new StringBuilder();
DoSomething(s => sb.AppendLine(s));
If you're calling from a place that doesn't care about the "return value", you can just omit the argument:
DoSomething();
But seriously, your design needs lots of work if you have to do something like this. Also, there's nothing wrong with return null - it's hard to see why that would be an issue in your code. Just replace all those return; with return null; or something. But it seems like your method simply does way too many things if you care about the distinction.
If you need your method to return void, you could use the out keyword to pass in your result as a reference variable, like this:
class Test
{
public string SendData(string val1){ return val1; }
public void RecoverBirth(out string result)
{
clsConnectionClass conn = new clsConnectionClass();
SqlCommand cmd = new SqlCommand();
SqlDataReader dr;
cmd.CommandText = "select * from birthday";
dr = cmd.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
result += SendData(dr[1].ToString() + " " + dr[2].ToString() + "\r\n");
}
}
}
}
And your call:
private void button_Click(object sender, EventArgs e)
{
var _test = new Test();
string result = null;
_test.RecoverBirth(out result);
}
I'm new to mvvm and I'm trying use a method "SaveAll"that saves the observablecollection to the database and I want to call it from a buttonclick event in code behind the view, but it doesn't seem to be possible.
This is the code I have so far. The error happens in NetworkViewModel.SaveAll(person)
namespace MyProject
{
using Model;
public class NetworkViewModel : INotifyPropertyChanged
{
private ObservableCollection<Person> _networkList1 = new ObservableCollection<Person>();
public ObservableCollection<Person> NetworkList1
{
get { return _networkList1; }
set { _networkList1 = value; RaisePropertyChanged("NetworkList1"); }
}
public NetworkViewModel()
{ }
public void SaveAll(Person person)
{
String dbConnectionString = #"Data Source =movieprepper.sqlite;";
SQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);
sqliteCon.Open();
var transaction = sqliteCon.BeginTransaction();
String DeleteQuery = "delete from networking";
SQLiteCommand DeleteCommand = new SQLiteCommand(DeleteQuery, sqliteCon);
DeleteCommand.ExecuteNonQuery();
foreach (Person p in _networkList1)
{
String Query = "insert into networking (firstname, lastname) values ('" + p.FirstName + "','" + p.LastName + "')";
SQLiteCommand Command = new SQLiteCommand(Query, sqliteCon);
Command.ExecuteNonQuery();
}
transaction.Commit();
sqliteCon.Close();
}
}
}
and in the code behind view I got this
namespace MyProject
{
public partial class Networking : Window
{
public Networking()
{
InitializeComponent();
this.DataContext = new NetworkViewModel();
}
private void btn_save_network_Click(object sender, RoutedEventArgs e)
{
NetworkViewModel.SaveAll(Person);// This is where error occurs
}
}
}
This doesn't seem to work I keep getting
"an object reference is required for the non static field, method or property"
I'm new to all this and trying to figure things out as I go but it seems I can't find the answer to this particular situation.
As mentioned, you should follow the command pattern for this. You can do so by updating your view model like this:
public class NetworkViewModel : INotifyPropertyChanged, ICommand
{
private ObservableCollection<Person> _networkList1 = new ObservableCollection<Person>();
public event EventHandler CanExecuteChanged;
public ObservableCollection<Person> NetworkList1
{
get { return _networkList1; }
set { _networkList1 = value; RaisePropertyChanged("NetworkList1"); }
}
public NetworkViewModel()
{ }
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
String dbConnectionString = #"Data Source =movieprepper.sqlite;";
SQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);
sqliteCon.Open();
var transaction = sqliteCon.BeginTransaction();
String DeleteQuery = "delete from networking";
SQLiteCommand DeleteCommand = new SQLiteCommand(DeleteQuery, sqliteCon);
DeleteCommand.ExecuteNonQuery();
foreach (Person p in _networkList1)
{
String Query = "insert into networking (firstname, lastname) values ('" + p.FirstName + "','" + p.LastName + "')";
SQLiteCommand Command = new SQLiteCommand(Query, sqliteCon);
Command.ExecuteNonQuery();
}
transaction.Commit();
sqliteCon.Close();
}
}
Since your SaveAll method did not actually use the Person (you loop over all of them in your collection instead), I wouldnt pass the People parameter along.
Then, instead of having your code behind invoke the method. You can bind your button to the view model. Your XAML would look like this:
<Button x:Name="SavButton"
Command="{Binding }"
Content="Save All People" />
If you wanted to save a specific person that you have selected, you can pass them along in your binding too
<Button x:Name="SavButton"
Command="{Binding }"
CommandParameter="{Binding Path=SelectedPerson}"
Content="Save All People" />
public void Execute(object person)
{
People p = (People)person;
// save......
}
That is assuming you have data bound the selected person to a property on your view model called SelectedPerson.
Hope this helps.
The technical correct answer would be that NetworkViewModel is a class name, you need a class instance to call your method on. For example the one you put into your DataContext earlier.
((NetworkViewModel)this.DataContext).SaveAll(Person);
But it would be better to read a about the command pattern that Microsoft wants you to use with WPF. It works a lot better with MVVM than your code behind.