graph line (X,Y,Z) control - c#

Hello I am searching for a graph that will allow me to make Z Line Graph control now I have X (Payment_Date) & Y (collected) line how to make Z (username) line
I want every username to have his line alone
Can someone help me?
I want to make the program on normal C# win form application
My Form
SqlDataReader reader = sqlcomm.ExecuteReader();
DataTable sd = new DataTable();
sd.Load(reader);
dataGridView1.DataSource = sd;
reader.Close();
chart1.Series["collected"].XValueMember = "Payment_Date";
chart1.Series["collected"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Date;
chart1.Series["collected"].YValueMembers = "collected";
chart1.Series["collected"].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
chart1.DataSource = sd;
chart1.DataBind();

Step one: Create a separate BindingSource for each element you want to bind and set an appropriate Filter so it will only display the data of one user each.
Step two: Show and hide the Series you want to.
I have created a DataTable dt with 3 columns:
dt.Columns.Add("User", typeof(string));
dt.Columns.Add("Date", typeof(DateTime));
dt.Columns.Add("Value", typeof(double));
and filled it randomly. Next I pull out the distinct users:
var users = dt.Rows.Cast<DataRow>()
.Select(x => x.Field<string>("User"))
.Distinct()
.OrderBy(x => x)
.ToList();
Most likely you will reverse this and start with a list of users.
Now I create a Series with its own filtered BindingSource for each user:
for (int i = 0; i < users.Count; i++)
{
Series s = chart1.Series.Add(users[i]);
s.ChartType = SeriesChartType.Line;
BindingSource bs = new BindingSource();
bs.DataSource = dt;
bs.Filter = "User='" + users[i] + "'";
s.Points.DataBindXY(bs, "Date", bs, "Value");
}
Now I bind my DGV:
BindingSource bsdgv = new BindingSource();
bsdgv.DataSource = dt;
bsdgv.Filter = "";
dataGridView1.DataSource = bsdgv;
I have hidden the Series by making them Transparent. This way the names still show in the Legend. The trick is to keep the original colors in the Series' Tags..:
void hideAllSeries(Chart chart)
{
chart.ApplyPaletteColors();
foreach (Series s in chart.Series)
{
if (s.Color != Color.Transparent) s.Tag = s.Color;
s.Color = Color.Transparent;
}
}
To show or hide a Series I code the MouseClick event:
private void Chart1_MouseClick(object sender, MouseEventArgs e)
{
var hitt = chart1.HitTest(e.X, e.Y);
if (hitt.ChartElementType == ChartElementType.LegendItem)
{
Series s = hitt.Series;
if (s.Color == Color.Transparent)
{
s.Color = (Color)s.Tag;
}
else
{
s.Tag = s.Color;
s.Color = Color.Transparent;
}
}
}
Let's see it at work:
Instead of this solution you may want to add a User selection Checklist and set the DGV's BindingSource's Filter..

Related

ComboBox added programmatically to DataGridView cell not expanding on cell click

I have a DataGridView in a C# WinForms project in which, when the user clicks on certain DGV cells, the cell changes to a DataGridViewComboBoxCell and the ComboBox is populated with some values for the user to select. Here's the form code for the DataGridView_Click event:
private void dgvCategories_Click(Object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 5 && !(dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name == "DataGridViewComboBoxCell"))
{
// Bind combobox to dgv and than bind new values datasource to combobox
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
// Get fields to build New Value query
List<string> lsNewValuesResult = new List<string>();
string strCategory = dtCategories.Rows[e.RowIndex][1].ToString();
string strCompanyName = cboSelectCompany.Text;
string strQueryGetNewValuesValidationInfo = "SELECT validationdb, validationtable, validationfield, validationfield2, validationvalue2" +
" FROM masterfiles.categories" +
" WHERE category = #category";
//" WHERE category = '" + strCategory + "'";
// Pass validation info query to db and return list of New Values
db getListOfNewValues = new db();
lsNewValuesResult = getListOfNewValues.GetNewValuesList(strQueryGetNewValuesValidationInfo, strCategory, strCompanyName);
//Populate the combobox with the list of New Values
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
//
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
}
}
Here's the code in the db class that populates the ComboBox (this likely isn't necessary to include for the purposes of this question, but for the sake of completeness, I'm including it, in case is it relevant):
public List<string> GetNewValuesList(string strValidationInfoQuery, string strCategory, string strCompanyName)
{
List<string> lsValidationInfo = new List<string>();
List<string> lsNewValuesList = new List<string>();
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(strValidationInfoQuery, conn))
{
cmd.Parameters.AddWithValue("category", strCategory);
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int intReaderIndex;
for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
{
// reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
{
lsValidationInfo.Add("");
}
else
{
lsValidationInfo.Add(reader.GetString(intReaderIndex));
}
//Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
}
}
}
}
string strValidationDb = lsValidationInfo[0];
string strValidationTable = lsValidationInfo[1];
string strValidationField = lsValidationInfo[2];
string strValidationField2 = lsValidationInfo[3];
string strValidationValue2 = lsValidationInfo[4];
string strQueryGetNewValues = "SELECT DISTINCT " + strValidationField +
" FROM " + strValidationDb + "." + strValidationTable +
" WHERE company_id = (SELECT id FROM company WHERE name = '" + strCompanyName + "')";
if (!string.IsNullOrEmpty(strValidationField2) && !string.IsNullOrEmpty(strValidationValue2)) strQueryGetNewValues += " AND " + strValidationField2 + " = '" + strValidationValue2 + "'";
strQueryGetNewValues += " ORDER BY " + strValidationField;
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(strQueryGetNewValues, conn))
{
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int intReaderIndex;
for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
{
// reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
{
lsNewValuesList.Add("");
}
else
{
lsNewValuesList.Add(reader.GetString(intReaderIndex));
}
Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
}
}
}
}
return lsNewValuesList;
}
The combobox is getting populated, as I can access the items in lsNewValuesResult in the _Click method. The DGV Edit Mode is set to EditOnEnter. I tried EditOnKeystroke, but that didn't cause the combobox to expand on mouse click.
This is what the combobox looks like when the cell is clicked on and the CBO is populated and added to the DGV cell:
That's after I clicked each of the two cells.
[RESOLVED]
See my Answer below.
Unfortunately solving this revealed a new issue.
I'm about to publicly admit that I'm stupid:
For design and functionality reasons that are required for this project, I am manually setting the widths and names of the DGV's columns, and I also need the 2nd through 4th columns ReadOnly = true. Well, I inadvertently set the 5th column - the column that this question is about to ReadOnly = true as well.
Thank you all for your attempts at answering. This just serves to remind us how something so simple can cause a seemingly big issue and is so easy to overlook!
If I recognize your problem correctly, in my test app i add a DataGridView whit 6 column, EditMode = EditOnEnter
(Others need three time click to open dropdown, As far as I tried) and handle CellStateChanged envent.
private void dgvCategories_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.StateChanged == DataGridViewElementStates.Selected)
{
DataGridViewCell cell = e.Cell;
int columnIndex = cell.ColumnIndex;
int rowIndex = cell.RowIndex;
//---IF CONDITIONS--
//columnIndex == 5
// Only cells in Columns[5]
//cell.Selected
// Because this event raised two time, first for last selected cell and once again
// for currently selected cell and we need only currently selected cell.
//cell.EditType.Name != "DataGridViewComboBoxEditingControl"
// If this cell "CellStateChanged" raised for second time, only other cell types allowed
// to edit, otherwise the current cell lost last selected item.
if (columnIndex == 5 && cell.Selected && cell.EditType.Name != "DataGridViewComboBoxEditingControl")
{
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
//Add items to DataGridViewComboBoxCell for test, replace it with yours.
for (int i = 0; i < 10; i++)
cboNewValueList.Items.Add($"Item {i}");
dgvCategories[columnIndex, rowIndex] = cboNewValueList;
}
}
}
NOTE: user must click two time in a cell to open drop down menu.
Edit One: As Reza Aghaei suggest for single click in cell:
private void dgvCategories_CellClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewComboBoxEditingControl editingControl = dgvCategories.EditingControl as DataGridViewComboBoxEditingControl;
if (editingControl != null)
editingControl.DroppedDown = true;
}
You might need to turn AutoGenerateColumns off:
Also, it seems to take a three clicks for the dropdown to pop.
public Form1()
{
InitializeComponent();
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = GetDataSource();
DataGridViewComboBoxColumn dgvcbc = new DataGridViewComboBoxColumn();
dgvcbc.Items.Add("R0C0");
dgvcbc.Items.Add("R1C0");
dgvcbc.Items.Add("R2C0");
dgvcbc.Items.Add("R3C0");
dgvcbc.DataPropertyName = "Col0";
dataGridView1.Columns.Add(dgvcbc);
}
DataTable GetDataSource()
{
var dtb = new DataTable();
dtb.Columns.Add("Col0", typeof(string));
dtb.Columns.Add("Col1", typeof(string));
dtb.Columns.Add("Col2", typeof(string));
dtb.Columns.Add("Col3", typeof(string));
dtb.Columns.Add("Col4", typeof(string));
dtb.Rows.Add("R0C0", "R0C1", "R0C2", "R0C3", "R0C4");
dtb.Rows.Add("R1C0", "R1C1", "R1C2", "R1C3", "R1C4");
dtb.Rows.Add("R2C0", "R2C1", "R2C2", "R2C3", "R2C4");
dtb.Rows.Add("R3C0", "R3C1", "R3C2", "R3C3", "R3C4");
return dtb;
}
Are you maybe getting an error which is not being shown for some reason?
If I use your code, DataGridViewComboBoxCell seems to be populated with values, but I get DataGridViewComboBoxCell value is not valid runtime error.
This test code is working fine for me:
private void dgvCategories_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
List<string> lsNewValuesResult = new List<string>();
lsNewValuesResult.Add("Value1");
lsNewValuesResult.Add("Value2");
lsNewValuesResult.Add("Value3");
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
// Added setting of initial value
cboNewValueList.Value = cboNewValueList.Items[0];
}
So maybe try setting the initial value for your DataGridViewComboBoxCell after you add it to the DataGridView.
You can consider the following facts about DataGridView:
If you set AutoGenerateColumns to false, then you need to add columns to Columns collection manually.
If you set AutoGenerateColumns to true, when you assign the data to DataSource, the control generates columns automatically for the data source. In this case, the control looks in list of columns of the data source and for each column if there's no column in the Columns collection of the control having the same DataPropertyName as data source's column name, it will add a column to Columns collection.
DataPropertyName of the datagridviews' columns determines the bound column of the data source.
You usually want to add DataGridViewXXXXColumn to columns collection rather than using a DataGridViewXXXXCell for a cell.
If you set EditMode to EditOnEnter, then if you click on dropdown button, one click is enough. If you click on cell content, two clicks is needed.
If you would like to make it single click even if you click on cell content, take a look at this post. (Note: I haven't used this is the example, it's a bit annoying.)
you can set DisplayStyle to Nothing, then it shows the column as a combo box, just in edit mode.
A basic example on using DataGridViewComboBoxColumn
I suppose you are going to show a list of Products having (Id, Name, Price, CategoryId) in a DataGridView and the CategoryId should come from a list of Categories having (Id, Name) and you are going to show CategoryId as a ComboBox.
In fact it's a basic and classic example of DataGridViewComboBoxColumn:
private void Form1_Load(object sender, EventArgs e) {
var categories = GetCategories();
var products = GetProducts();
var idColumn = new DataGridViewTextBoxColumn() {
Name = "Id", HeaderText = "Id", DataPropertyName = "Id"
};
var nameColumn = new DataGridViewTextBoxColumn() {
Name = "Name", HeaderText = "Name", DataPropertyName = "Name"
};
var priceColumn = new DataGridViewTextBoxColumn() {
Name = "Price", HeaderText = "Price", DataPropertyName = "Price"
};
var categoryIdColumn = new DataGridViewComboBoxColumn() {
Name = "CategoryId", HeaderText = "Category Id", DataPropertyName = "CategoryId",
DataSource = categories, DisplayMember = "Name", ValueMember = "Id",
DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing
};
dataGridView1.Columns.AddRange(idColumn, nameColumn, priceColumn, categoryIdColumn);
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = products;
}
public DataTable GetProducts() {
var products = new DataTable();
products.Columns.Add("Id", typeof(int));
products.Columns.Add("Name", typeof(string));
products.Columns.Add("Price", typeof(int));
products.Columns.Add("CategoryId", typeof(int));
products.Rows.Add(1, "Product 1", 100, 1);
products.Rows.Add(2, "Product 2", 200, 2);
return products;
}
public DataTable GetCategories() {
var categories = new DataTable();
categories.Columns.Add("Id", typeof(int));
categories.Columns.Add("Name", typeof(string));
categories.Rows.Add(1, "Category 1");
categories.Rows.Add(2, "Category 2");
return categories;
}
Learn more
To learn more about DataGridView, take a look at DataGridView Control (Windows Forms). It contains links to some documentations and useful How To articles, including:
DataGridView Control Overview
Basic Column, Row, and Cell Features in the Windows Forms DataGridView Control
Basic Formatting and Styling in the Windows Forms DataGridView Control
Column Types in the Windows Forms DataGridView Control

Winforms bindingsource issue adding new record

I have the following code to load an bind data to master-detail window, where master data bound to textboxes and other controls and detail data bound to DataGridView:
ON FORM LOAD:
DataSet dsOrders = new DataSet("dsOrders");
SqlDataAdapter daOrderHeader;// = new SqlDataAdapter();
SqlDataAdapter daOrderDetail;// = new SqlDataAdapter();
BindingSource bsOrderHeader = new BindingSource();
BindingSource bsOrderDetail = new BindingSource();
DataTable dtOrderHeader = new DataTable("dtOrderHeader");
DataTable dtOrderDetail = new DataTable("dtOrderDetail");
dsOrders.Tables.Add(dtOrderHeader);
dsOrders.Tables.Add(dtOrderDetail);
daOrderHeader = DataAdapterOrderHeader();
daOrderDetail = DataAdapterOrderDetail();
daOrderHeader.Fill(dtOrderHeader);
daOrderDetail.Fill(dtOrderDetail);
////Set up a master-detail relationship between the DataTables
DataColumn keyOrderHeaderColumn = dsOrders.Tables["dtOrderHeader"].Columns["ID"];
DataColumn foreignKeyOrderDetailColumn = dsOrders.Tables["dtOrderDetail"].Columns["OrderId"];
dsOrders.Relations.Add("rOrders", keyOrderHeaderColumn, foreignKeyOrderDetailColumn);
bsOrderHeader.DataSource = dsOrders;
bsOrderHeader.DataMember = "dtOrderHeader";
bsOrderDetail.DataSource = bsOrderHeader;
bsOrderDetail.DataMember = "rOrders";
tbxOrderNo.DataBindings.Add("Text", bsOrderHeader, "ID");
tbxCustomer.DataBindings.Add("Text", bsOrderHeader, "Name");
tbxTaxRate.DataBindings.Add("Text", bsOrderHeader, "TaxRate");
tbxShipping.DataBindings.Add("Text", bsOrderHeader, "Shipping");
tbxExchangeRate.DataBindings.Add("Text", bsOrderHeader, "ExchangeRate");
dtpOrderDate.DataBindings.Add("Text", bsOrderHeader, "OrderDate");
cbxPriceCode.DataBindings.Add("SelectedIndex", bsOrderHeader, "PriceCode");
dgvItems.DataSource = bsOrderDetail;
enter code here
ON ADD NEW RECORD:
DataRow drOrderHeader = dsOrders.Tables["dtOrderHeader"].NewRow();
drOrderHeader["ID"] = (maxID + 1);
dsOrders.Tables["dtOrderHeader"].Rows.Add(drOrderHeader);
DataRow drOrderDetail = dsOrders.Tables["dtOrderDetail"].NewRow();
drOrderDetail["OrderId"] = (maxID + 1);
dsOrders.Tables["dtOrderDetail"].Rows.Add(drOrderDetail);
bsOrderHeader.DataSource = dsOrders.Tables["dtOrderHeader"];
bsOrderDetail.DataSource = dsOrders.Tables["dtOrderDetail"];
When I click add new row button, bindingsource.count property shows that new record has been added, but winform controls stay on the same record and I am not able scroll to newly created record, also bindingsource.movelast stoped working.
Any suggestion please? What I need is to scroll to newly added record/row with all winform textboxes cleared and ready to enter data for new record, except OrderId that I generate and in this code at the time of creation
UPDATE: Made changes to Add button, but unsuccessfull
newOrderId = Convert.ToInt32(dsOrders.Tables["dtOrderHeader"].Compute("max(ID)", string.Empty)) + 1;
DataRow drOrderHeader = dsOrders.Tables["dtOrderHeader"].NewRow();
drOrderHeader["ID"] = (newOrderId);
dsOrders.Tables["dtOrderHeader"].Rows.Add(drOrderHeader);
DataRow drOrderDetail = dsOrders.Tables["dtOrderDetail"].NewRow();
drOrderDetail["OrderId"] = (newOrderId);
dsOrders.Tables["dtOrderDetail"].Rows.Add(drOrderDetail);
bsOrderHeader.Position = bsOrderHeader.Find("ID", newOrderId);
As you already found, data binding detects the changes you've made in the underlying data sources, thus the following two lines:
bsOrderHeader.DataSource = dsOrders.Tables["dtOrderHeader"];
bsOrderDetail.DataSource = dsOrders.Tables["dtOrderDetail"];
are redundant. And not only that, but the second changes incorrectly the data source type of the bsOrderDetail. So simply remove them.
In order to rebind the UI to the newly added record, all you need is to set the Position property of the bsOrderHeader to the index of the new record like this:
bsOrderHeader.Position = bsOrderHeader.Find("ID", drOrderHeader["ID"]);
and the data binding infrastructure will automatically rebind both master controls and (via DataRelation) the detail grid view.
EDIT: Here is full working demo. If your code doesn't work after the update, it should be caused by some other code part not shown in the post.
using System;
using System.Data;
using System.Windows.Forms;
namespace Samples
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form();
DataSet dsOrders = new DataSet("dsOrders");
//SqlDataAdapter daOrderHeader;// = new SqlDataAdapter();
//SqlDataAdapter daOrderDetail;// = new SqlDataAdapter();
BindingSource bsOrderHeader = new BindingSource();
BindingSource bsOrderDetail = new BindingSource();
DataTable dtOrderHeader = new DataTable("dtOrderHeader");
DataTable dtOrderDetail = new DataTable("dtOrderDetail");
dsOrders.Tables.Add(dtOrderHeader);
dsOrders.Tables.Add(dtOrderDetail);
//daOrderHeader = DataAdapterOrderHeader();
//daOrderDetail = DataAdapterOrderDetail();
//daOrderHeader.Fill(dtOrderHeader);
//daOrderDetail.Fill(dtOrderDetail);
dtOrderHeader.Columns.Add("ID", typeof(int));
dtOrderHeader.Columns.Add("Name", typeof(string));
dtOrderHeader.Columns.Add("TaxRate", typeof(decimal));
dtOrderHeader.Columns.Add("Shipping", typeof(string));
dtOrderHeader.Columns.Add("ExchangeRate", typeof(decimal));
dtOrderHeader.Columns.Add("OrderDate", typeof(DateTime));
dtOrderHeader.Columns.Add("PriceCode", typeof(int));
dtOrderHeader.PrimaryKey = new[] { dtOrderHeader.Columns["ID"] };
dtOrderDetail.Columns.Add("OrderId", typeof(int));
dtOrderDetail.Columns.Add("Quantity", typeof(decimal));
////Set up a master-detail relationship between the DataTables
DataColumn keyOrderHeaderColumn = dsOrders.Tables["dtOrderHeader"].Columns["ID"];
DataColumn foreignKeyOrderDetailColumn = dsOrders.Tables["dtOrderDetail"].Columns["OrderId"];
var rel = dsOrders.Relations.Add("rOrders", keyOrderHeaderColumn, foreignKeyOrderDetailColumn);
bsOrderHeader.DataSource = dsOrders;
bsOrderHeader.DataMember = "dtOrderHeader";
bsOrderDetail.DataSource = bsOrderHeader;
bsOrderDetail.DataMember = "rOrders";
var splitView = new SplitContainer { Dock = DockStyle.Fill, Parent = form };
var tbxOrderNo = new TextBox();
var tbxCustomer = new TextBox();
var tbxTaxRate = new TextBox();
var tbxShipping = new TextBox();
var tbxExchangeRate = new TextBox();
var dtpOrderDate = new DateTimePicker();
int y = 8;
foreach (var c in new Control[] { tbxOrderNo, tbxCustomer, tbxTaxRate, tbxShipping, tbxExchangeRate, dtpOrderDate })
{
c.Top = y;
c.Left = 16;
splitView.Panel1.Controls.Add(c);
y = c.Bottom + 8;
}
var dgvItems = new DataGridView { Dock = DockStyle.Fill, Parent = splitView.Panel2 };
tbxOrderNo.DataBindings.Add("Text", bsOrderHeader, "ID");
tbxCustomer.DataBindings.Add("Text", bsOrderHeader, "Name");
tbxTaxRate.DataBindings.Add("Text", bsOrderHeader, "TaxRate");
tbxShipping.DataBindings.Add("Text", bsOrderHeader, "Shipping");
tbxExchangeRate.DataBindings.Add("Text", bsOrderHeader, "ExchangeRate");
dtpOrderDate.DataBindings.Add("Text", bsOrderHeader, "OrderDate");
//cbxPriceCode.DataBindings.Add("SelectedIndex", bsOrderHeader, "PriceCode");
dgvItems.DataSource = bsOrderDetail;
Func<DataRow> addOrder = () =>
{
var maxOrderId = dsOrders.Tables["dtOrderHeader"].Compute("max(ID)", string.Empty);
int newOrderId = (maxOrderId != null && maxOrderId != DBNull.Value ? Convert.ToInt32(maxOrderId) : 0) + 1;
DataRow drOrderHeader = dsOrders.Tables["dtOrderHeader"].NewRow();
drOrderHeader["ID"] = newOrderId;
dsOrders.Tables["dtOrderHeader"].Rows.Add(drOrderHeader);
DataRow drOrderDetail = dsOrders.Tables["dtOrderDetail"].NewRow();
drOrderDetail["OrderId"] = newOrderId;
dsOrders.Tables["dtOrderDetail"].Rows.Add(drOrderDetail);
return drOrderHeader;
};
for (int i = 0; i < 5; i++) addOrder();
var addButton = new Button { Dock = DockStyle.Bottom, Parent = form, Text = "Add" };
addButton.Click += (sender, e) =>
{
var drOrderHeader = addOrder();
bsOrderHeader.Position = bsOrderHeader.Find("ID", drOrderHeader["ID"]);
};
Application.Run(form);
}
}
}

MsChart Add Multiple Series from Database

I want to add different line chart one at the time to my chart. So i have a textbox with a button . i input a code and load the series from my database. The problem is that the new line series override the old line series. so i decided to keep tract of the added series into a gridview, i loop through it and fill the chart; same result.
This is my code
void AddSerie(string stockName)
{
try
{
Legend legend = new Legend(stockName);
Chart1.Legends.Add(legend);
Series series = new Series(stockName);
Chart1.Series.Add(series);
string[] _data = new string[3];
_data[0] = stockName;
_data[1] = "2010-01-01";
_data[2] = "2015-03-15";
DataSet ds = DBSelect(_data, "web_price_series");
Chart1.DataSource = ds;
Chart1.Series[stockName].XValueMember = "tdate";
Chart1.Series[stockName].YValueMembers = "value";
Chart1.Series[stockName].ChartType = SeriesChartType.Line;
Chart1.DataBind();
}
catch (Exception)
{
throw;
}
}
this is how i call the method
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
AddSerie(row.Cells[0].Text);
}
}
and i have the legend showing two series but the chart displays only one line.
i added this picture to show the second output of the chart for two companies using MarkerStyle.
This is an example of what i want to achieve .
This is the structure of the table
any help?
Instead of using the databind i used another method:
Chart1.Series[0].Points.AddXY(XValues, Yalues);
void AddSerie(string stockName)
{
try
{
Legend legend = new Legend(stockName);
Chart1.Legends.Add(legend);
Series series = new Series(stockName);
Chart1.Series.Add(series);
string[] _data = new string[3];
_data[0] = stockName;
_data[1] = "2010-01-01";
_data[2] = "2015-03-15";
DataSet ds = DBSelect(_data, "web_price_series");
Chart1.DataSource = ds;
Chart1.Series[stockName].XValueMember = "tdate";
Chart1.Series[stockName].YValueMembers = "value";
Chart1.Series[stockName].ChartType = SeriesChartType.Line;
foreach (DataRow row in ds.Tables[0].Rows)
{
Chart1.Series[stockName].Points.AddXY(row[0], row[1]);
}
// Chart1.DataBind();
}
catch (Exception)
{
throw;
}
}

Create a Details Form from a GridView c#

Possibly a complex question - but here's hoping
I have a generic data grid on a single form (displays whatever table I want from a dataset) simply by swapping tables in the dataset.
I want to double-click on a given record and display a single-record view of the table data with the currently selected record displayed as default, but with the option to page through and edit/view/delete other records i.e.
I want to automatically create a details view form from a datagrid for a given table at runtime. The form should be dynamically created - displaying the dataset in details view with the option to page through single records using the binding source/binding source navigator.
My goal is to improve efficiency/maintainability of the application - rather than create and manage 10+ forms, I simply want to create and manage I generic details form in the same way as I manage I generic gridview form.
So far I have come up with:
public void CreateDetailsForm(BindingSource bs, int rowClicked)
{
Form detailsForm = new Form();
BindingSource newFormBS = new BindingSource();
//assign binding source for use on new detailsForm
newFormBS = bs;
//assign binding source to datatable
DataTable dt = (DataTable)bs.DataSource;
//create the form fields
CreateFormFields(dt); //not yet implemented
//assign form fields to form
//display form
}
Any help on the following appreciated
Generating and assigning the form fields to the form.
Thanks in advance.
it likes:
Form f=new Form();
TextBox t=new TextBox();//generate the controls u need
t.Text = "test";//set the actual value
t.Location=new Point(10,10);
f.Controls.Add(t);
DialogResult dr=f.ShowDialog();
So far I have got the col names generated on the form as follows
List colNames = GetColumnNames(dt);
int offset=25;
int xPos=50;
int yPos = 10;
foreach (string name in colNames)
{
Label l = new Label();
l.Name = name;
l.Width = 200;
l.Text = name;
TextBox t = new TextBox();
t.Name = name;
t.Width=200;
l.Location = new Point(xPos, yPos );
t.Location = new Point(xPos+250, yPos);
f.Controls.Add(l);
f.Controls.Add(t);
yPos = yPos + offset;
}
//TextBox t = new TextBox();//generate the controls u need
//t.Text = "test";//set the actual value
f.Width = 800;
f.Height = 600;
f.Show();
}
private List<string> GetColumnNames(DataTable table)
{
List<string> lstColNames=new List<string>();
if (table != null)
{
lstColNames=
(from DataColumn col in table.Columns
select col.ColumnName).ToList();
}
return lstColNames;
}
Now trying to work on getting the controls to bind to the binding source!
OK - got it working now - had to take a different approach
Created a single detailsView Form
Created a static class called PassBindingSource with a static property bst for passing binding source from gridview to details form
static class PassBindingSource
{
public static BindingSource bst { get; set; }
}
On the detailsView form added the following code
try{ bs.DataSource = PassBindingSource.bst;
DataTable dt = (DataTable)PassBindingSource.bst.DataSource;
List<string> colNames = GetColumnNames(dt);
int offset = 25;
int xPos = 50;
int yPos = 50;
foreach (string name in colNames)
{
Label l = new Label();
l.Name = name;
l.Width = 200;
l.Text = name;
TextBox t = new TextBox();
t.Name = name;
t.Width = 200;
// BindingOperations.SetBinding(t, t.TextProperty, bs);
//binding operation
t.DataBindings.Add(new Binding("Text", bs, t.Name, true));
l.Location = new Point(xPos, yPos);
t.Location = new Point(xPos + 250, yPos);
this.Controls.Add(l);
this.Controls.Add(t);
yPos = yPos + offset;
// dgDetailsView.DataSource = bs;
}
//move to correct record in binding source
bs.Position = PassBindingSource.currentRecord;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private List<string> GetColumnNames(DataTable table)
{
List<string> lstColNames=new List<string>();
if (table != null)
{
lstColNames=
(from DataColumn col in table.Columns
select col.ColumnName).ToList();
}
return lstColNames;
}
SUMMARY
Now it all works - the detailsView controls generated at run-time wired up correctly to the binding source and the datagrid can call this detailsView any time using any table from the dataset by wiring the double-click event of the gridview with the following code
PassBindingSource.bst= bs;
frmDetailsView nf = new frmDetailsView();
nf.Show();
Hope this helps others. Many thanks to User2354374 for the initial steer.

zed graph: how to make my graph start at 0,0

I want my graph to start at 0,0 but right now it is starting at the time that the data starts (because i don't know what a better alternative for xdatamember would be to get my desired results. any suggestions?
private void Form1_Load(object sender, EventArgs e)
{
dataAdapter = new SqlDataAdapter(strSQL, strCon);
commandBuilder = new SqlCommandBuilder(dataAdapter);
// Populate a new data table and bind it to the BindingSource.
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
dataAdapter.Fill(table);
bindingSource.DataSource = table;
// Resize the DataGridView columns to fit the newly loaded content.
dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
// you can make it grid readonly.
dataGridView.ReadOnly = true;
// finally bind the data to the grid
dataGridView.DataSource = bindingSource;
GraphPane myPane = height.GraphPane;
// Create a new DataSourcePointList to handle the database connection
DataSourcePointList dspl = new DataSourcePointList();
// Specify the table as the data source
dspl.DataSource = table;
dspl.XDataMember = "age";
dspl.YDataMember = "height";
LineItem Curve1 = myPane.AddCurve("student 1", dspl, Color.pink, SymbolType.None);
height.AxisChange();
myPane.Chart.Fill = new Fill(Color.White, Color.LightGray, 45.0F);
// set the title and axis labels
myPane.Title.Text = "student heights";
myPane.XAxis.Title.Text = "age";
myPane.YAxis.Title.Text = "height";
myPane.XAxis.Type = AxisType.Date;
}
First, I did a quick search for this sort of thing and found this: Lock axis in ZedGraph
You can set the XAxis.Min and YAxis.Min to whichevers value you want shown as the min of the respective Axes. My code from my test looked like this:
//static ZedGraph.ZedGraphControl graph = new ZedGraph.ZedGraphControl();
ZedGraph.GraphPane pane = graph.GraphPane;
pane.XAxis.Scale.Min = 0.0;
graph.AxisChange();
graph.RestoreScale(pane);
graph.ZoomOut(pane);

Categories

Resources