I'm working on a method that is static, and returns a value off a WinForm, it spawns the new form on a button click, and upon hitting the submit or cancel buttons it throws back its value.
The issue is, I cant refer to a combobox control on my form to populate it with the results of my sqlreader.
I have read suggestions that I use a wrapper that looks akin to
public ComboBox comboHolder { get return this.foo }
however I can't seem to refer to it either. Any suggestions to remedy this ?
Full code
public ComboBox comboboxWrapper
{
get { return this.comboUsernames; }
}
public static string SelectProfile()
{
Form selectProfile = new Select_Profile();
selectProfile.ShowDialog();
SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Users.mdf;Integrated Security=True;Connect Timeout=30");
connection.Open();
SqlCommand command = new SqlCommand("SelectAllUsers", connection);
SqlDataReader usersReader = command.ExecuteReader();
List<string> accountNames = new List<string>();
while (usersReader.Read())
{
accountNames.Add((string)usersReader["Username"]);
}
//populate the combo box
foreach (string s in accountNames)
{
//I'd like to call comboboxWrapper here.
}
//set the combo box to have a default item
// combo.SelectedIndex = 0;
}
Also, this is a work in progress, I realize I should have some try, catch and a finally statement, other than that i'm open to any suggestions for code improvement.
Thanks!
I would suggest just not making the method static. But if you really need to for some reason, you could pass a reference to the form into your static method, e.g.:
SelectProfile(Form myForm)
Then you would be able to use it inside the method like this:
foreach (string s in accountNames)
{
// e.g myForm.comboboxWrapper
}
your static method need object of class for that you have to pass object of class where comboboxwrapper defined
public static string SelectProfile(ClassobjectofCoboboxWrapper obj)
{
obj.comboboxWrapper;
}
Call to this method from outside
SelectProfile(new ClassobjectofCoboboxWrapper())
Note:
As static method are not related to instace of object its related to class. So to refer element in static method which are not static you either need to create object of refering class or you need to pass object of class your want to refer.
This is your form instance:
Form selectProfile = new Select_Profile();
So you'd call comboboxWrapper on that instance:
selectProfile.comboboxWrapper
Though first you'll need to change its type, since Form doesn't have a member called comboboxWrapper. Declare it like this instead:
Select_Profile selectProfile = new Select_Profile();
or simply:
var selectProfile = new Select_Profile();
Even though the comboboxWrapper member is defined outside the static method, it's inside the form instance. A static member has no default notion of a particular instance and needs to be provided with one. Or, in this case, internally creates one.
First, decompose your solution: just don't cram database and UI into single method. Next think over what your method is supposed to return as a String:
public static IEnumerable<String> AccountNames() {
//TODO: Move it into Settings/Config...
String connectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Users.mdf;Integrated Security=True;Connect Timeout=30";
// Dispose (via using) all Disposable...
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
// Dispose: prevent resource leakage...
using (SqlCommand command = new SqlCommand("SelectAllUsers", connection)) {
using (SqlDataReader usersReader = command.ExecuteReader()) {
while (usersReader.Read())
yield return (string)usersReader["Username"];
}
}
}
}
// returns selected profile
// or null if no profile was seelcted
public static string SelectProfile() {
// var: You need Select_Profile, not just a Form, right?
// again (using): don't forget to clear up the resources
using (var selectProfile = new Select_Profile()) {
// Providing that comboboxWrapper is public (bad practice)
// or SelectProfile() is implemented within Select_Profile class (good one)
selectProfile.comboboxWrapper.Items.AddRange(AccountNames());
if (selectProfile.comboboxWrapper.Items.Count > 0)
selectProfile.comboboxWrapper.SelectedIndex = 0;
if (selectProfile.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if (selectProfile.comboboxWrapper.SelectedIndex < 0)
return null; // No item to select
else
selectProfile.comboboxWrapper.SelectedItem.ToString();
}
else
return null; // Just closed
}
}
Related
I have created a simplified SQL Data class, and a class method for returning a ready to use resultset:
public SQL_Data(string database) {
string ConnectionString = GetConnectionString(database);
cn = new SqlConnection(ConnectionString);
try {
cn.Open();
} catch (Exception e) {
Log.Write(e);
throw;
}
}
public SqlDataReader DBReader(string query) {
try {
using (SqlCommand cmd = new SqlCommand(query, this.cn)) {
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
} catch {
Log.Write("SQL Error with either Connection String:\n" + cn + " \nor Query:\n" + query);
throw;
}
}
(I catch any errors, log them, and then catch the error higher up the chain. Also, I did not include the ConnectionString() code for brevity. It just returns the requested connection string. That's all.)
This all works just fine, and with a single line of code, I'm ready to .Read() rows.
SqlDataReader rs = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees");
while (rs.Read()) {
// code
}
rs.Close();
I want to expand this and add a .ColumnReader() method that I want to chain to .DBReader() like this:
string empID = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees).ColumnReader("EmpID");
I attempted this by adding a .ColumnReader() method, but it ends up being a method of SQL_Data() class directly, not a member or extension of .DBReader(). I also tried adding the .ColumnReader() inside the .DBReader() (like a "closure"), but that didn't work either.
Can this be done?
This ended up working for me:
public static class SQLExtentions {
public static dynamic ColumnReader(this SqlDataReader rs, string colName) {
return rs[colName];
}
}
I will have to expand on it a bit to add some error checking, and perhaps return more than just the dynamic value - like return an object with the value and it's SQL data type. But Paul and Bagus' comments got me on the right track.
I am using an external class which implements IDisposable and an external method which populates an instance of that class.
I am looking for a neat way to encapsulate the disposable object in a "using" statement but can't work out the syntax.
Let's say the class is ...
class Something : IDisposable
And the function is ...
void PopulateSomething(Something theObject)
I could do this ...
Something myObject = new Something();
PopulateSomethingObject(myObject);
x = myObject.SomeNumber;
myObject.Dispose();
or I could also do this ...
Something myObject = new Something();
using(myObject)
{
x = myObject.SomeNumber;
}
but neither of the above are great because after disposal I could stupidly write something like this
x = myObject.SomeNumber; // which will throw an exception
I suppose I could do this ...
using(Something myObject = new Something())
{
PopulateSomethingObject(myObject);
x = myObject.SomeNumber();
}
But I would like to believe something like the following is possible but I can't figure out the syntax...
using (Something myObject => PopulateSomethingObject(myObject = new Something()))
{
x = myObject.SomeNumber();
}
I guess it's sort of a theoretical question because I don't really have a problem here but I am curious to know if it is possible. i.e. Instantiate the object and pass it to a method within the declaration of the "using(...){} block.
Here's what you could do
private Something CreateAndPopulate()
{
var myObject = new Something();
PopulateSomethingObject(myObject);
return myObject;
}
And then use it like:
using (var myObject = CreateAndPopulate())
{
x = myObject.SomeNumber();
}
Update1
One other way to do that could be by writing an Extension for Something like
public static class SomethingExtension
{
public static Something Populate(this Something someObj, Action<Something> actionToPopulate)
{
actionToPopulate.Invoke(someObj);
return someObj;
}
}
And then using it in a single line like:
using (var myObject = new Something().Populate(PopulateSomethingObject))
{
x = myObject.SomeNumber();
}
Update2
Fianlly, one line way to do it could look complicated
using (var myObject = new Func<Something>(() =>
{
var myNewObject = new Something();
PopulateSomethingObject(myNewObject);
return myNewObject;
}).Invoke())
{
//x = myObject.SomeNumber();
}
The problem is the signature of the PopulateSomething method, which prevents you from creating and using Something objects in a single expression. Since PopulateSomething's return type is void, it must be used as a statement, not as an expression.
Your last approach that compiles is pretty good:
using (Something myObject = new Something()) {
PopulateSomethingObject(myObject);
x = myObject.SomeNumber();
}
In fact, it is similar to the pattern used with database connections, when the object created inside using undergoes some additional configuration before use:
using (conn = factory.CreateConnection()) {
// Do more things to conn before its first use.
conn.ConnectionString = "...";
conn.Open();
... // Use conn here
}
If you would like to avoid the call to PopulateSomethingObject inside using, make a factory method returning Something, like this:
private static Something GetAndConfigure() {
Something res = new Something();
PopulateSomethingObject(res);
return res;
}
Now you can write
using (Something myObject = GetAndConfigure()) {
x = myObject.SomeNumber();
}
using(Something myObject = new Something())
{
PopulateSomethingObject(myObject);
x = myObject.SomeNumber();
}
This is the correct usage of a USING block. You create the instance inside the brackets.
If you really didnt want to dispose the object then you shouldnt be using the USING in the first place.
No, you should put only objects inside using.
And for my point of view the idea is not so good. I see two parts of code - the first path creates the object, and the second - processes it. And you try to mix the first part with the second. I think that the last option is less readable than
using(Something myObject = new Something())
{
PopulateSomethingObject(myObject);
x = myObject.SomeNumber();
}
I've been trying to create a new base class for a Windows Forms form. I want to have this base class go through all the tableadapters it has on it and update their connection strings without anyone adding any code to the form. They just put the tableadapters on the form and don't worry about the connection string settings as it's all handled in the base class.
The problem is my reflection code can find the property fine, but it can't set it. How can I fix it?
Below is the code:
public class cFormWS : Form
{
public string ConnectionStringToUse { get; set; }
public cFormWS()
{
Load += cFormWS_Load;
}
void cFormWS_Load(object sender, EventArgs e)
{
InitiliseTableAdapters();
}
private void InitiliseTableAdapters()
{
var ListOfComponents = EnumerateComponents();
foreach (var ItemComp in ListOfComponents)
{
if (ItemComp.ToString().ToLower().EndsWith("tableadapter"))
{
var ItemCompProps = ItemComp.GetType().GetRuntimeProperties();
var TASQLConnection =
ItemCompProps.FirstOrDefault(
w => w.PropertyType == typeof(System.Data.SqlClient.SqlConnection));
if (TASQLConnection != null)
{
var property = typeof(System.Data.SqlClient.SqlConnection).GetProperty("ConnectionString");
// How do I set the value?
string value = "some new connection string";
var ConvertedProperty = Convert.ChangeType(value, property.PropertyType);
// I tried seting a value. It is not working:
// "object does not match target type"
property.SetValue(TASQLConnection, ConvertedProperty, null);
//// I tried using a method. It is not working:
//// "object does not match target type"
//var m = property.SetMethod;
//ParameterInfo[] parameters = m.GetParameters();
//m.Invoke(m, parameters); // m.Invoke(this, parameters); // m.Invoke(ItemComp, parameters);
}
}
}
}
private IEnumerable<Component> EnumerateComponents()
{
return from field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
where typeof(Component).IsAssignableFrom(field.FieldType)
let component = (Component)field.GetValue(this)
where component != null
select component;
}
When you do SetValue, you need to pass in the object that you wish to set the property on.
In your first example code, you passed in ItemComp: This is incorrect, since the ConnectionString is a property of the SqlConnection which is a property of ItemComp
In your edited question (and my original answer) you pass in the TASqlConnection. However, this is not the object, but a PropertyInfobased of the object
The correct way is to get the value from the ItemComp object and pass that in:
property.SetValue(TASQLConnection.GetValue(ItemComp), ConvertedProperty, null);
ORIGINAL (INCORRECT) ANSWER:
You're trying to set a ConnectionString property of ItemComp. The ConnectionString is not a property of the TableAdapter, but of the SqlConnection (which is a property of the TableAdapter).
The correct way of setting the property would be this:
property.SetValue(TASQLConnection, ConvertedProperty, null);
I have this code that queries a database. I want to put the actual database code into a separate class so I can reuse it in other places. This will leave just the actual read of the PassResult value so I can make a Unit Test of the code without having the SQL code running. I am having trouble finding references on how to make this kind of code Unit Testable. Could someone help out?
using System;
using System.Data;
using System.Data.SqlClient;
namespace CS_UI_Final_Inspection
{
public class CalibrationTestCheck
{
// declare the variables
private bool _calibrationTestPass = false;
private string _connectionString = string.Empty;
public bool CheckCalibrationTestResults(string serialNumber, IDeviceInfo deviceInfo, string mapID)
{
// get database location
DhrLocationPull dhrLocation = new DhrLocationPull();
_connectionString = dhrLocation.PullDhrLocation();
// build the query
SqlConnection calibrationCheckConnection = new SqlConnection(_connectionString);
SqlCommand calibrationCheckCommand = new SqlCommand("[MfgFloor].[GetLatestTestResultsForDeviceByTestType]",
calibrationCheckConnection);
// build the stored proc
calibrationCheckCommand.CommandType = CommandType.StoredProcedure;
calibrationCheckCommand.Parameters.Add(new SqlParameter("#SerialNumber", serialNumber));
calibrationCheckCommand.Parameters.Add(new SqlParameter("#DeviceTypeID", mapID));
calibrationCheckCommand.Parameters.Add(new SqlParameter("#TestDataMapTypeID", "C"));
calibrationCheckCommand.Connection.Open();
SqlDataReader calibrationCheckReader = calibrationCheckCommand.ExecuteReader();
// is there data?
if (calibrationCheckReader.HasRows)
{
// read the data
calibrationCheckReader.Read();
try
{
_calibrationTestPass = (bool) calibrationCheckReader["PassResult"];
}
catch (InvalidOperationException)
{
// means last element was not filled in
}
finally
{
// close refs
calibrationCheckReader.Close();
calibrationCheckCommand.Connection.Close();
calibrationCheckConnection.Close();
calibrationCheckReader.Dispose();
calibrationCheckCommand.Dispose();
calibrationCheckConnection.Dispose();
}
}
return _calibrationTestPass;
}
}
}
create an interface and implement it.
move all references to be tested to use the interface (exposing any methods/properties required through the interface)
have the constructor or method being tested take the interface as a parameter.
Roy Oscherov is a good resource on this. Roy Oscherov wrote a great book called "The art of unit testing". Roy's website can be found here: http://osherove.com/
I am working on a project where I am converting some VB.Net class libraries to C# libraries (mostly to learn C# syntax). My problem is that I cannot get the Save function working.
I am building my object with this:
public static StoreEmployee Create(string LoginId)
{
var emp = new StoreEmployee();
using (var dt = DAC.ExecuteDataTable("usp_ActiveEmployeeSelect",
DAC.Parameter(CN_LoginId, LoginId)))
{
emp.StoreId = Convert.ToString(dt.Rows[0][CN_StoreId]);
emp.FirstName = Convert.ToString(dt.Rows[0][CN_FirstName]);
emp.LastName = Convert.ToString(dt.Rows[0][CN_LastName]);
emp.UserName = Convert.ToString(dt.Rows[0][CN_UserName]);
emp.Role = Convert.ToString(dt.Rows[0][CN_Role]);
emp.Description = Convert.ToString(dt.Rows[0][CN_Description]);
}
return emp;
}
And then creating it with this
private static void FillStoreEmployeeObject(string empLoginId)
{
StoreEmployee.Create(empLoginId);
}
And then trying to use this save function to save the object back to the database:
public override Boolean Save(string LoginId)
{
try
{
int retVal = DAC.ExecuteNonQuery("usp_ActiveEmployeeSave",
DAC.Parameter(CN_LoginId, LoginId),
DAC.Parameter(CN_StoreId, StoreId),
DAC.Parameter(CN_FirstName, FirstName),
DAC.Parameter(CN_UserName, UserName),
DAC.Parameter(CN_Role, Role),
DAC.Parameter(CN_Description, Description));
return true;
}
catch
{
return false;
}
}
I don't get a syntax warning for that but I have revised it many times so I want to make sure that is correct before I move on. Does this look correct? By the way I am trying to call the Save function with this
StoreEmployee.Save(Convert.ToString(Login))
which gives me this error An object reference is required for the non-static field, method, or property However when I mark my function as static my Create function shows errors so I am left very confused.
Save is an instance method.
As the error message states,you need to call it on an existing instance of StoreEmployee (such as the one returned by Create).