I'm have a Windows Form with 2 datetimepicker controls: one for date and a separate datetimepicker control for time. Both of these controls are bound to the same column in a database and the controls have different property names (i.e., dateEdit and timeEdit) and different formats (i.e., Long and Time).
Here are my problems/questions:
The timeEdit picker ignores whatever seconds are in the database entry and sets the time seconds to "00", as in "2:34:00", even though the database entry (trimmed to time for this illustration) is "14:34:31.891123 -04:00". How can I get the seconds to correctly display?
Whenever I edit the seconds in the timeEdit picker from "00" to (for example) "15", as in "2:34:15", the picker resets the seconds to "00" before passing the value to the next function. How do I pass the correct seconds value?
I'd like to edit the milliseconds on the time. Is it best for me to bind the trimmed milliseconds (using DATEPART) to a text box? Will I need to convert or cast the milliseconds to a char or string in order to correctly display them in a text box?
Thanks for any help!
Code to trigger the edit form:
private void timeDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex == 5)
{
EditTime editForm = new EditTime((Guid)timeDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
editForm.StartPosition = FormStartPosition.CenterScreen;
editForm.ShowDialog();
editForm.Close();
}
}
catch (Exception ex)
{
string msg = "Error: ";
msg += ex.Message;
throw new Exception(msg);
}
}
Code for the form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace StatusManager
{
public partial class EditTime : Form
{
private Guid calendarId;
public EditTime()
{
InitializeComponent();
}
public EditTime(Guid Id)
{
InitializeComponent();
calendarId = Id;
}
public string GetConnectionString()
{
var connString = ConfigurationManager.ConnectionStrings["StatusManager.Properties.Settings.StatusConnectionString"].ConnectionString;
return connString;
}
private void UpdateCalendarItem(string dateEdit, string timeEdit, string note)
{
var conn = new SqlConnection(GetConnectionString());
const string UpdateStatusSql = #"UPDATE dbo.statuses SET
calendarTime = #timeOffset
notes = #note
WHERE PK_calendarUID = #PK_calendarUID";
try
{
SqlCommand cmd = new SqlCommand(UpdateSql, conn);
var param = new SqlParameter[3];
param[0] = new SqlParameter("#PK_calendarUID", calendarId);
//Convert date(s) to correct format
string dateTimeCombined = dateEdit + " " timeEdit;
DateTime timeConverted = Convert.ToDateTime(dateTimeCombined);
DateTimeOffset timeOffset = new DateTimeOffset(timeConverted);
param[1] = new SqlParameter("#timeOffset", timeOffset);
param[2] = new SqlParameter("#note", note);
foreach (SqlParameter t in param)
{
cmd.Parameters.Add(t);
}
conn.Open();
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
string msg = "Error updating 'calendarItems': ";
msg += ex.Message;
throw new Exception(msg);
}
finally
{
conn.Close();
}
}
private void editTimeButton_Click(object sender, EventArgs e)
{
UpdateCalendarItem(dateEdit.Text, timeEdit.Text, notes.Text);
this.Close();
}
private void EditTime_Load(object sender, EventArgs e)
{
this.locationsTableAdapter.Fill(this.locationsDataSet.locations);
this.calendarTableAdapter.FillById(this.calendarDataSet.calendarItems, calendarId);
}
}
}
Code for instantiating the datetimepicker:
this.timeEdit.CustomFormat = "";
this.timeEdit.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.calendarBindingSource, "calendarTime", true));
this.timeEdit.Format = System.Windows.Forms.DateTimePickerFormat.Time;
this.timeEdit.Location = new System.Drawing.Point(385, 30);
this.timeEdit.Name = "timeEdit";
this.timeEdit.ShowUpDown = true;
this.timeEdit.Size = new System.Drawing.Size(89, 20);
this.timeEdit.TabIndex = 2;
You need to use DateTimePicker.CustomFormat Property
s The one- or two-digit seconds.
ss The two-digit seconds. Single digit values are preceded by a 0.
You can't use DateTimePicker for milliseconds.
Problem solved but I'm not exactly sure how. Here's what I did:
In calendarDataSet, I updated both queries (Fill,GetData and FillById,GetDataBy (#ID)) to select calendarTime as CONVERT(VARCHAR(12), calendarTime, 114) AS calHoursMinsSec
In essence, I created created a new column with the hours, minutes, seconds, and milliseconds
On the form, I added a textbox and bound the textbox to calHoursMinsSec
Note: My previous attempts to convert the datetime to a varchar to were unsuccessful no doubt due to operator error.
Once I saved the form, the binding seemed to stick and I was able to pass the relevant variables to the update function
Thanks for everyone's input! I appreciate the guidance and suggestions!
Related
I have a winform, that takes a number of params, executes an stored procedure and then populates a DataGridView with the results.
What I'd like to do is add a string the bottom of my winform that returns a message, including a count of total rows returned.
This presently works fine, using the following syntax :
deskSearchResultCount.Text = String.Format("Your search returned {0} results", deskDataGridView.RowCount );
However as the majority of my application has been written out in the initial form, I was moving sections into classes, to 'tidy it up' a bit - (I'm still very new to c# so apologies if this is a n00b mistake)
Once I add a class called Summary, I would like to call my RowCount as follows :
Summary Returned = new Summary();
deskSearchResultCount.Text = String.Format("Your search returned {0} results", Returned.Total("Desk"));
With my Summary class containing the following :
public class Summary : ContactAnalysisToolbox
{
public int Total(string type)
{
if (type == "Desk")
{
return deskDataGridView.Rows.Count;
}
else
{
return visionDataGridView.Rows.Count;
}
}
However the returned count is always 0. When stepping through the process also, at no point does it appear to be attempting to set itself as anything different.
Can anyone please help / point me in the right direction?
Thanks.
Edit -
I've included the full form also -
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.DirectoryServices.AccountManagement;
using System.IO;
//
// Todo :
// -- Capture Assigned Team In Output
//
//
namespace CallsAnalysisToolbox
{
public partial class ContactAnalysisToolbox : Form
{
public ContactAnalysisToolbox()
{
InitializeComponent();
// Grabs username for current user and displays a welcome message
this.welcomeMessage.Text = "Welcome " + UserPrincipal.Current.Name;
}
private void searchVision_Click(object sender, EventArgs e)
{
try
{
// Run sp_incomingCalls on SQLCLUSTER
this.rep_IncomingCallsTableAdapter.Fill(this.visionReportsDataSet.Rep_IncomingCalls, dateTimePicker1.Value, dateTimePicker2.Value, textBox1.Text, textBox2.Text);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
// Make export button active when search returns results
exportVisionButton.Enabled = (visionDataGridView.Rows.Count > 0);
// Assign returned row count to visionSearchResultCount label and then display label
visionSearchResultCount.Text = String.Format("Your search returned {0} results", visionDataGridView.RowCount);
visionSearchResultCount.Visible = true;
}
private void searchDesk_Click(object sender, EventArgs e)
{
try
{
// Run sp_caseActivity on SQLCLUSTER
this.rPT_CaseActivityTableAdapter.Fill(this.deskDataSet.RPT_CaseActivity, deskFrom.Value, deskTo.Value, deskClientList.Text, deskBenefitList.Text, deskStatusList.Text);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
if (deskDataGridView.Rows.Count > 0)
{
exportDeskButton.Enabled = true;
deskSearchResultCount.Visible = true;
Summary Returned = new Summary();
deskSearchResultCount.Text = String.Format("Your search returned {0} results", Returned.Total("Desk"));
deskSummaryData.Visible = true;
noDataDesk.Visible = false;
// Populate the summary tab
// Get Email / Phone case count
deskTotalCaseResults.Text = deskDataGridView.RowCount.ToString();
//deskTotalEmailCasesResults.Text = emailCount.ToString();
//deskTotalPhoneCasesResults.Text = phoneCount.ToString();
}
}
//TODO : Combine Export functions. Ideally just a single function rather than the repeated logic within the Export class for each datagrid
private void exportVisionButton_Click(object sender, EventArgs e)
{
Export Export = new Export();
Export.ReturnedResult("Vision");
}
private void exportDeskButton_Click(object sender, EventArgs e)
{
Export Export = new Export();
Export.ReturnedResult("Desk");
}
private void deskDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Limit 'open case in browser' action to first cell
if (deskDataGridView.CurrentCell.ColumnIndex.Equals(0))
{
string url = string.Format("https://qa.internal.local/agent/case/{0}", deskDataGridView.Rows[e.RowIndex].Cells[0].Value);
Process.Start(url);
}
}
}
}
For example you could do something like this. It's called Method Extension
Try this
public static class Helpers
{
public static string ToTotalCount(this DataGridView item)
{
return string.Format("Your search returned {0} results", item.Rows.Count);
}
}
In your form make sure that the namespace of the class Helpers is in the usings:
deskSearchResultCount.Text = deskDataGridView.ToTotalCount();
I am fairly new to C# programming and am having some trouble figuring out how to perform this. I am trying to say in the program that if the textBoxes are not filled in than streamWriter should not send anything to the file and a messageBox pops up. As of now only the messageBox pops up but information is still being sent to the file. I am trying to use something like this if ((fileOut != null)) however I am not finding a good place to insert it or if this is what should be used. Any help would be much appreciated. Thanks!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Calculate payroll
private void btnCalculate_Click(object sender, EventArgs e)
{
try
{
decimal hoursWorked;
decimal hourlyPayRate;
decimal basePay;
decimal overtimeHours;
decimal overtimePay;
decimal grossPay;
// Get the hours worked and hourly pay rate.
hoursWorked = decimal.Parse(txtHoursWorked.Text);
hourlyPayRate = decimal.Parse(txtHourlyRate.Text);
// Determine the gross pay.
if (hoursWorked >= 40)
{
// Calculate the base pay (without overtime).
basePay = hourlyPayRate * 40;
// Calculate the number of overtime hours.
overtimeHours = hoursWorked - 40;
// Calculate the overtime pay.
overtimePay = overtimeHours * hourlyPayRate * 1.5m;
// Calculate the gross pay.
grossPay = basePay + overtimePay;
}
else
{
// Calculate the gross pay.
grossPay = hoursWorked * hourlyPayRate;
}
// Display the gross pay.
lblGrossPay.Text = Convert.ToString(grossPay);
}
catch (Exception ex)
{
// Display an error message.
MessageBox.Show(ex.Message);
} //Writes text to files
StreamWriter fileOut = new StreamWriter("employeePay.dat", true);
//if (!(fileOut != null))//I am trying this. However stated this way nothing is passed to the file
{
fileOut.Write(txtName.Text);
fileOut.Write(",");
fileOut.Write(txtNumber.Text);
fileOut.Write(",");
fileOut.Write(txtHourlyRate.Text);
fileOut.Write(",");
fileOut.Write(txtHoursWorked.Text);
fileOut.Write(",");
fileOut.WriteLine(lblGrossPay.Text);
}
fileOut.Close();
LoadContacts();
}
// Clear all text from output labels & input textboxes
private void btnClera_Click(object sender, EventArgs e)
{
// Clear the TextBoxes and gross pay label.
txtName.Text = "";
txtNumber.Text = "";
txtHoursWorked.Text = "";
txtHourlyRate.Text = "";
lblGrossPay.Text = "";
// Reset the focus.
//txtHoursWorked.Focus();
}
// End program
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
void LoadContacts()
{
try
{
lstEmployeePay.Items.Clear();
string employeePay;
if (File.Exists("employeePay.dat"))
{
StreamReader fileIn = new StreamReader("employeePay.dat");
while (!fileIn.EndOfStream)
{
employeePay = fileIn.ReadLine();
string[] fields = employeePay.Split(',');
lstEmployeePay.Items.Add(fields[0]);
lstEmployeePay.Items.Add(fields[1]);
lstEmployeePay.Items.Add(fields[2]);
lstEmployeePay.Items.Add(fields[3]);
lstEmployeePay.Items.Add(fields[4]);
lstEmployeePay.Items.Add("");
}
fileIn.Close();
}
}
catch (FileNotFoundException ex)
{
MessageBox.Show("The file does not exist, please try again");
}
catch (Exception ex)
{
}
}
}
}
All you need is a return statement after showing the message box. Like
MessageBox.Show("");
return;
I would also like to make some other recommendations here.
You can check if the textboxes are empty by doing
if(string.IsNullorWhiteSpace(yourtextboxt.text)
You should do the parsing using decimal.tryparse. It will not throw an exception.
You need to move your stream writer within the exception handling as everything after the catch still gets executed.
I would also consider wrapping the StreamWriter in a using statement to guarantee it is closed when the function exits.
try
{
// other code here
using(var fileOut = new StreamWriter("employeePay.dat", true)
{
fileOut.Write(txtName.Text);
fileOut.Write(",");
fileOut.Write(txtNumber.Text);
fileOut.Write(",");
fileOut.Write(txtHourlyRate.Text);
fileOut.Write(",");
fileOut.Write(txtHoursWorked.Text);
fileOut.Write(",");
fileOut.WriteLine(lblGrossPay.Text);
}
}
catch(...)
{
MessageBox();
}
// any code after the catch will still execute
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Cameron_PickerillTrinitapoli_Assn1
{
public partial class seasonalBttnChanger : Form
{
public seasonalBttnChanger()
{
InitializeComponent();
}
//Triggers when program first loads
//Sets up
private void bttnChanger_Load(object sender, EventArgs e)
{
List<Button> lstTxt = new List<Button>
{
bttnSpring, bttnSummer, bttnAutumn, bttnWinter
};
//Wiring up event handlers in run time
foreach (Button txt in lstTxt)
{
txt.MouseEnter += button_MouseEnter;
txt.MouseLeave += button_MouseLeave;
}
}
// Sets up different background colors for TextBoxes
//* Static values for the color of each button need
//to be added.
//**Not what I was trying to accomplish
//**This needs to go somewhere else
void button_MouseEnter(object sender, EventArgs e)
{
try
{
// Event handlers always pass the parameter "sender" in as an object.
// You have to downcast it back to the actual type.
String bttnName = null;
String bttnNameSpring = "Spring";
String bttnNameSummer = "Summer";
String bttnNameAutumn = "Autumn";
String bttnNameWinter = "Winter";
Button txt = (Button)sender;
// stkColor.Push(txt.BackColor);
//txt.BackColor = Color.Red;
bttnName = txt.Name;
if (bttnName == bttnNameSpring)
{
txt.BackColor = Color.LightGreen;
}
else if (bttnName == bttnNameSummer)
{
//txt.BackColor = Color.Red;
txt.BackColor = Color.Red;
}
else if (bttnName == bttnNameAutumn)
{
txt.BackColor = Color.Yellow;
}
else if (bttnName == bttnNameWinter)
{
txt.BackColor = Color.Cyan;
}
}
catch (Exception ex)
{
MessageBox.Show("Error:\n " + ex.Message);
}
}
//Handler for mouse leaving the button
void button_MouseLeave(object sender, EventArgs e)
{
try
{
Button txt = (Button)sender;
//txt.BackColor = stkColor.Pop();
}
catch (Exception ex)
{
MessageBox.Show("Error:\n " + ex.Message);
}
}
}
}
}
Alright, so I'm just trying to create a simple program that changes the background colors of these buttons to some plain colors when you mouse over them. I had the same thing working using TextBox, but I need to get it working with button. I changed everything over to use the Button class, and it seems to have all the same functionality, but now the program runs, but nothing happens when you mouse over the buttons.
I'm pretty new to c#, stack exchange, and only slightly less so to programming in general, so sorry if I'm dinking up on etiquette/formatting my questions, etc.
I think you are trying to reference your buttons title when you are actually calling the button name
Changing:
String bttnName = null;
String bttnNameSpring = "Spring";
String bttnNameSummer = "Summer";
String bttnNameAutumn = "Autumn";
String bttnNameWinter = "Winter";
Button txt = (Button)sender;
To:
String bttnName = null;
String bttnNameSpring = "bttnSpring";
String bttnNameSummer = "bttnSummer";
String bttnNameAutumn = "bttnAutumn";
String bttnNameWinter = "bttnWinter";
Causes the code to work.
If you do infact want to use the "Spring", "Summer" etc reference than i would suggest changing
bttnName = txt.Name;
to
bttnName = txt.Text;
And ensure that the Text of the labels is set correctly
This question already has answers here:
C# - Winforms - Global Variables
(8 answers)
Closed 9 years ago.
I have been trying, without success, to share a variable between multiple forms. I am very new to c# and so have been failing miserably despite reading a couple of things about it.. Below is the programs code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;
using System.Data.OleDb;
namespace login
{
public partial class LoginScreen : Form
{
public LoginScreen()
{
InitializeComponent();
}
// Variables
int count = 0;
public static System.Data.OleDb.OleDbConnection con =
new System.Data.OleDb.OleDbConnection();//database connection
string dbProvider;
string dbSource;
OleDbDataAdapter da; // create database adapter 'da'
// CREATE DATASET VARIABLE ds1 TO HOLD THE DATABASE
public static DataSet ds1 = new DataSet();
string accountNo;
string sql;
string password;
int rownum = 0;
bool valid = false;
private void btnLogin_Click(object sender, EventArgs e)
{
accountNo = txtBoxAccntNo.Text;
valid = validate(); //uses validate() method to check validity
if (valid == true && accountNo == "11111111")
{
ManagerScreen Manager = new ManagerScreen();
this.Hide();
Manager.Show();
}
else if (valid == true)
{
s customer = new s();
this.Hide();
customer.Show();
}
else
{
if (count == 2)
{
this.Close();
}
count += 1;
txtBoxAccntNo.Clear();
txtBoxPinNo.Clear();
}
}
private void txtBoxAccntNo_TextChanged(object sender, EventArgs e)
{
}
private void LoginScreen_Load(object sender, EventArgs e)
{
// open database connection and load contents
// database connection
dbProvider = "PROVIDER=Microsoft.ACE.OLEDB.12.0;"; // this is the database provider
dbSource = "Data Source = 'C:\\Bank.accdb'"; // navigation path
con.ConnectionString = dbProvider + dbSource;
}
private void btnExit_Click(object sender, EventArgs e)
{
// If button exit selected hide this form and open the welcome screen
WelcomeForm Welcome = new WelcomeForm();
this.Hide();
Welcome.Show();
}
// IsValid method checks that pass and login are valid
private bool validate()
{
ds1 = new DataSet();
con.Open();
// Validate Account number
sql = "SELECT * FROM tblCustomers WHERE ((tblCustomers.AccountNo) = '" + txtBoxAccntNo.Text + "')";
da = new OleDbDataAdapter(sql, con);
rownum = da.Fill(ds1, "tblCustomers");
con.Close();
if (rownum != 1)
{
MessageBox.Show("Not a valid Account number! - Try Again ");
return false;
}
else
{
// validate the pin
password = ds1.Tables["tblCustomers"].Rows[0][4].ToString();
if (password == txtBoxPinNo.Text)
{
MessageBox.Show("valid");
return true;
}
else
{
MessageBox.Show("Not a valid password - please try again ");
return false;
}
}
}
}
}
I want to share the variable accountNo with all other forms. Please advise, as I really need to get on with this. Thank you for any help.
You can make that accountNo property as static or either you can have some getter method to access that too.
If you set accountNo as static you can access it by just calling
ClassName.PropertyName
in your case
LoginScreen.accountNo will be the account number property.
Simple code sample
public partial class LoginScreen : Form
{
public LoginScreen()
{
InitializeComponent();
}
public static string accountNo;
}
public class AnotherClass
{
string accountNo = LoginScreen.accountNo;
}
The right way to go about this is to use the form to retrieve the information and then store it somewhere else to be accessed as you need it. Don't access it directly in the form from elsewhere - this will require you to keep the login form in scope for the whole application lifecycle. This probably isn't what you want.
In practice, this means creating something like a Global static class that everything has access to:
public static class Globals {
public static string AccountNumber {
get;
set;
}
}
From in your login form, after validating the login as correct, you would simply do:
Globals.AccountNumber = txtBoxAcctNo.Text;
Then, anywhere else you need the AccountNumber, you can access it as Globals.AccountNumber.
I can recommend one of three ways to achieve what you want:
Make accountNo a public static variable. Then, other forms can access it by LoginScreen.accountNo (it's better to have a property to control visibility). This is a good approach if you might have many active instances of LoginScreen and they all might update accountNo and you want any form which accesses this field to get the latest value.
Implement a singleton pattern for the entire form and have accountNo in it as a public variable. This is a good approach if you will only have one instance of the firm active at any time.
Have accountNo be static member in another class and have LoginScreen access it by UtilClass.accountNo. This is a good approach if other forms/classes might want to update the field and/or it's a field which shouldn't be associated with this form.
i created a winforms application. what it does is it queries a database and displays the data on a chart on the screen.
my question is, is it proper to use classes for this? i know the answer is probably yes, but i have no clue how to use a class for this,.
here is my code. please give me a few pieces of advice on how to turn this into a class if you think that is the right thing to do:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Data.OleDb;
using System.Data.SqlClient;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private DataTable qResults = new DataTable();
private void Form1_Load(object sender, EventArgs e)
{
string qcvalues_query = "SELECT DISTINCT name FROM qvalues ORDER by name";
string analytes_query = "SELECT DISTINCT compound FROM qvalues ORDER by compound";
string instruments_query = "SELECT DISTINCT instrument FROM batchinfo WHERE instrument <> '' AND instrument is not Null ORDER by instrument";
dataGridView1.MultiSelect = false;
cbAnalytes.DisplayMember = "name";
cbAnalytes.DataSource = ConnectandReadList(qcvalues_query);
cbQCValues.DisplayMember = "compound";
cbQCValues.DataSource = ConnectandReadList(analytes_query);
cbInstruments.DisplayMember = "instrument";
cbInstruments.DataSource = ConnectandReadList(instruments_query);
}
private DataSet GetSeriesValues()
{
Series ser = this.chart1.Series["Series1"];
DataSet dataSet = new DataSet();
DataTable seriesTable = new DataTable(ser.Name);
seriesTable.Columns.Add(new DataColumn("No", typeof(int)));
seriesTable.Columns.Add(new DataColumn("X", typeof(string)));
seriesTable.Columns.Add(new DataColumn("Y", typeof(double)));
for (int count = 0; count < ser.Points.Count; count++)
{
DataPoint p = ser.Points[count];
seriesTable.Rows.Add(new object[] { count, p.XValue, p.YValues[0] });
}
dataSet.Tables.Add(seriesTable);
return dataSet;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
// Call Hit Test Method
HitTestResult result = chart1.HitTest(e.X, e.Y);
// Reset Data Point Attributes
foreach (DataPoint point in chart1.Series[0].Points)
{
point.BackSecondaryColor = Color.Black;
point.BackHatchStyle = ChartHatchStyle.None;
point.BorderWidth = 1;
}
// If a Data Point or a Legend item is selected.
if
(result.ChartElementType == ChartElementType.DataPoint ||
result.ChartElementType == ChartElementType.LegendItem)
{
try
{
// Set cursor type
this.Cursor = Cursors.Hand;
// Find selected data point
DataPoint point = chart1.Series[0].Points[result.PointIndex];
// Set End Gradient Color to White
point.BackSecondaryColor = Color.White;
// Set selected hatch style
point.BackHatchStyle = ChartHatchStyle.Percent25;
// Increase border width
point.BorderWidth = 2;
}
catch { }
}
else
{
// Set default cursor
this.Cursor = Cursors.Default;
}
}
private void InitializeChart()
{
chart1.Series["Series1"].ChartType = SeriesChartType.Line;
chart1.Series["Series1"].MarkerStyle = MarkerStyle.Circle;
chart1.Series["Series1"].MarkerSize = 8;
// Set series members names for the X and Y values
chart1.Series["Series1"].XValueMember = "datapath";
chart1.Series["Series1"].YValueMembers = "finalconc";
chart1.DataBind();
// Calculate Mean
double mean = chart1.DataManipulator.Statistics.Mean("Series1");
// Calculate Median
double median = chart1.DataManipulator.Statistics.Median("Series1");
// Calculate Standard Deviation from the Variance
double variance = chart1.DataManipulator.Statistics.Variance("Series1", true);
double standardDeviation = Math.Sqrt(variance);
// Set Strip line item
chart1.ChartAreas[0].AxisY.StripLines[0].IntervalOffset = mean - Math.Sqrt(variance);
chart1.ChartAreas[0].AxisY.StripLines[0].StripWidth = 2.0 * Math.Sqrt(variance);
// Set Strip line item
chart1.ChartAreas[0].AxisY.StripLines[1].IntervalOffset = mean;
// Set Strip line item
chart1.ChartAreas[0].AxisY.StripLines[2].IntervalOffset = median;
DataPoint maxValuePoint = chart1.Series["Series1"].Points.FindMaxByValue();
DataPoint minValuePoint = chart1.Series["Series1"].Points.FindMinByValue();
chart1.ChartAreas[0].AxisY.Maximum = maxValuePoint.YValues.Max();
chart1.ChartAreas[0].AxisY.Minimum = minValuePoint.YValues.Min();
// Refresh Chart
chart1.Invalidate();
}
private DataTable ConnectandReadList(string query)
{
DataTable ds = new DataTable();
string connection_string = "Data Source=hermes;database=qcvalues; Integrated Security=SSPI;";
using (var myConnection = new SqlConnection(connection_string))
{
myConnection.Open();
var command = new SqlCommand(query, myConnection);
var adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
}
return ds;
}
private void btnGenerateGraph_Click(object sender, EventArgs e)
{
string graph_query = #"SELECT top 1000 reporttime,
datapath,
finalconc,
instrument
FROM batchinfo
JOIN qvalues ON batchinfo.rowid = qvalues.rowid
WHERE compound = '" + cbQCValues.Text + "'" +
"AND name = '" + cbAnalytes.Text + "'" +
"AND batchinfo.instrument = '" + cbInstruments.Text + "'" +
"AND batchinfo.reporttime LIKE '10/%/2010%'";
qResults = ConnectandReadList(graph_query);
if (qResults.Rows.Count == 0)
{
MessageBox.Show("Your query did not return any results!");
return;
}
chart1.DataSource = qResults;
InitializeChart();
dataGridView1.Columns.Clear();
dataGridView1.DataBindings.Clear();
dataGridView1.DataSource = qResults;
}
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
// Call Hit Test Method
HitTestResult result = chart1.HitTest(e.X, e.Y);
if (result.ChartElementType == ChartElementType.DataPoint)
{
dataGridView1.Rows[result.PointIndex].Selected = true;
dataGridView1.FirstDisplayedScrollingRowIndex = result.PointIndex;
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
Int32 selectedRowCount =
dataGridView1.Rows.GetRowCount(DataGridViewElementStates.Selected);
if (selectedRowCount == 1)
{
qResults.Rows.RemoveAt(dataGridView1.SelectedRows[0].Index);
InitializeChart();
}
}
}
}
How you organize your code depends on the scale and complexity of your application.
If you are writing a large application you probably want to use different layers to deal with the database, business logic and presentation.
For a small application like yours it is probably simpler to use data binding directly to a database query.
You are already using classes, but not the cleanest, most modular way. It's generally thought a bad idea to combine your data manipulation and business logic in a single UI class. This is why the MVC composite pattern was invented, to separate your data, the UI and biz logic into more modular pieces.
Here's another article, C# specific, to look at.
I think this is a subjective question... If it works already, why fix it?
But from another point of view, if this was part of a larger system, I would split it up not just into separate classes, but separate assemblies and namespaces.
You code is correct, for the task at hand. I would not worry about it right now, unless you are already a proficient programmer (know the syntax) and the goal is to implement good modular system design for a larger scale system.
I'm with slaks on this. Form1 is a class.
The only real change I would possibly suggest at this point would be to turn that into a composite control. That way you could drop that functionality onto different forms as necessary.
Check out the MS walkthrough and a smaller article here.
You might do that for no other reason than to learn something new.