I am trying to add the column names of a gridview to a dropdown list.
The problem is when I change the datasource of the gridview, it returns empty.
I am not sure whether the event is working properly, as it does not work with/without it.
I wanted to use the DataBindComplete event, but I could not see it so I tried DataBound instead.
private void BindTable()
{
if (ddTableSearch.SelectedIndex == 0)
{
tblCustomerTableAdapter customerAdapter = new tblCustomerTableAdapter();
GridView2.DataSource = customerAdapter.GetData();
GridView2.DataBind();
}
else if (ddTableSearch.SelectedIndex == 1)
{
tblInvoiceTableAdapter invoiceAdapter = new tblInvoiceTableAdapter();
GridView2.DataSource = invoiceAdapter.GetData();
GridView2.DataBind();
}
else if (ddTableSearch.SelectedIndex == 2)
{
tblEstimateTableAdapter estimateAdapter = new tblEstimateTableAdapter();
GridView2.DataSource = estimateAdapter.GetData();
GridView2.DataBind();
}
}
protected void GridView2_DataBound(object sender, EventArgs e)
{
// Populate dropdown with column names
ddColumnSearch.Items.Clear();
for (int i = 0; i < GridView2.Columns.Count; i++)
{
ddColumnSearch.Items.Add(new ListItem(GridView2.Columns[i].ToString()));
}
}
What am I doing wrong?
The databound event runs for each record in the gridview. So one issue is that each time you are clearing out the items you added before. Another issue is that you need to get the data from the EventArgs instead of from the gridview.columns since those are not there until after all the data is bound. I think all you need to do is get the data from the header row:
protected void GridView2_DataBound(object sender, EventArgs e)
{
// Populate dropdown with column names
if(e.Row.RowType != DataControlRowType.Header) return; //only continue if this is hdr row
ddColumnSearch.Items.Clear();
foreach (TableCell cell in e.Row.Cells)
{
ddColumnSearch.Items.Add(new ListItem(cell.Text));
}
}
Related
I want to add a new row to datagridview after validating the row. I call my AddNewRow method inside of the RowValidated event. But it gives "Operation cannot be performed in this event handler" error.
My datagridview is not bounded any data source, and AllowUsersToAddRow property is setted to false.
DataGridView have only one column, which is named "Cost".
Here is my code;
private void RMaterialDGV_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (dgv.IsCurrentRowDirty)
{
if(dgv.CurrentRow.Cells["Cost"].Value == null || dgv.CurrentRow.Cells["Cost"].Value.ToString().Length == 0
|| dgv.CurrentRow.Cells["Cost"].Value.ToString() == 0.ToString())
{
e.Cancel = true;
}
}
}
private void RMaterialDGV_RowValidated(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (dgv.CurrentRow.Index == dgv.Rows.Count - 1 && dgv.CurrentRow.Cells["Cost"].Value != null)
{
if (dgv.CurrentRow.Cells["Cost"].Value.ToString().Length > 0)
AddNewRowToDGV();
}
}
private void AddNewRowToDGV()
{
int index = RMaterialDGV.Rows.Add();
RMaterialDGV.Rows[index].Cells["Cost"].Value = 0;
}
I use this method to add new rows before(other projects) but never get these error.
What am I missing?
Thanks in advance.
Rows cannot be programmatically added to the DataGridView's rows collection when the control is data-bound.
Instead you can add rows to your datasource. Update your AddNewRowToDGV method to something like below.
private void AddNewRowToDGV()
{
var data = (DataTable) dataGridView1.DataSource;
var row = data.NewRow();
row["Cost"] = 1;
data.Rows.Add(row);
}
I solved this problem creating a DataTable and binding this DataTable to my DataGridView. But I can't really understand what cause the actual problem.
I am Developing a winforms application. I have two datagrid views populated from two different bindingsources(control). I am using these to implement the master detail approach. My problem is that when the first datagridview is populated using the binding source I can't select the first row of it ,because the first element in the binding source is defaultly selected and can't be selected. Can any one provide me a solution for this
As you say the first row is selected by default. So after populating the DataSource to your first GridView you can set the second GridView based on first entry. Later you check the selectionChanged Event to populate the second GridView based on selectedRow of your first one.
Code could look sth. like this:
private void PopulateDataSource()
{
dataGridView1.DataSource = myBindingSource;
DataRowView selectedRow;
if (dataGridView1.SelectedRows.Count > 0)
selectedRow = dataGridView1.SelectedRows[0] as DataRowView;
if (selectedRow != null)
dataGridView2.DataSource = myBindingSource2; //Set the BindingSource based on selectedRow in first Grid
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
DataRowView selectedRow;
if (dataGridView1.SelectedRows.Count > 0)
selectedRow = dataGridView1.SelectedRows[0] as DataRowView;
if (selectedRow != null)
dataGridView2.DataSource = myBindingSource2; //Set the BindingSource based on selectedRow in first Grid
}
If this doesn't work let me know but should do the job.
UDPATE
Here is a similar example using the events and methods of the bindingSource:
private void Initialize()
{
RegisterBindingSourceEvents();
dataGridView1.DataSource = bindingSource1;
dataGridView2.DataSource = bindingSource2;
bindingSource1.DataSource = myDataSource;
}
private void RegisterBindingSourceEvents()
{
bindingSource1.DataSourceChanged += BindingSource1_DataSourceChanged;
bindingSource1.CurrentChanged += BindingSource1_CurrentChanged;
}
private void BindingSource1_CurrentChanged(object sender, EventArgs e)
{
DataRowView row = bindingSource1.Current as DataRowView;
if (row != null)
bindingSource2.DataSource = myDataSource2BasedOnRow;
}
private void BindingSource1_DataSourceChanged(object sender, EventArgs e)
{
DataRowView row = bindingSource1.Current as DataRowView;
if (row != null)
bindingSource2.DataSource = myDataSource2BasedOnRow;
}
Further you maybe can use:
bindingSource.MoveNext();
bindingSource.MoveFirst();
To simulate focusing seconde row and directly first row. A bit ugly but i would guess this fires current_changed (untested). Better use first approach.
UDPATE-2
I'm sorry to tell you that this is not possible in a beautiful manner. The problem is that the Current Property of your bindingList is always set if your DataSource contains items. So if the user select the same row as the bindingSource Current Property contains your event won't get called. I found a solution which works in my example. You will need one gridEvent and maybe have to do some improvments but the idea should do the job. Sorry but without gridEvent i can't solve this:
Notice that iam using List as DataSource for my Testcase. You got DataTable and have to cast to DataRowView instead of Dummy for sure.
private bool _automatedRowChange;
private void Initialize()
{
List<Dummy> dummies = new List<Dummy> { new Dummy { Id = 1, Text = "Test1" }, new Dummy { Id = 2, Text = "Test2" } };
bindingSource1.DataSource = dummies;
dataGridView1.DataSource = bindingSource1;
//So the first row isn't focused but the bindingSource Current Property still holds the first entry
//That's why it won't fire currentChange even if you click the first row. Just looks better for the user i guess
dataGridView1.ClearSelection();
bindingSource1.CurrentChanged += BindingSource1_CurrentChanged;
dataGridView1.CellClick += DataGridView1_CellClick;
}
private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
var clickedRow = dataGridView1.Rows[e.RowIndex].DataBoundItem as Dummy;
var currentRow = bindingSource1.Current as Dummy;
if (clickedRow != null &&
currentRow != null &&
clickedRow.Equals(currentRow))
{
_automatedRowChange = true;
bindingSource1.MoveNext();
_automatedRowChange = false; //MovePrevious is based on the click and should load the dataSource2
bindingSource1.MovePrevious();
}
}
private void BindingSource1_CurrentChanged(object sender, EventArgs e)
{
if (!_automatedRowChange) //Check if you jump to next item automatically so you don't load dataSource2 in this case
{
//Set the second DataSource based on selectedRow
}
}
Hi all I would like to change cell index based on certain value like shown below ,I have seen many articles in here, but in ASP.NET this is a windows app how can I archive this thanks with a windows desktop app.Please Note the column that I want indexes changed is created dynamically.Thanks
Dynamic column code creation
private void button3_Click(object sender, EventArgs e)
{
DataTable table = new DataTable();
adap.Fill(table);
dataGridView1.DataSource = table;
table.Columns.Add("RESULTS").Expression = "Iif(((ActualWeight >= (.96 * TargetWeight)) And (ActualWeight <= (1.04 * TargetWeight))),'GOOD''BAD'))
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[7].Value.ToString() == "BAD")
row.Cells[7].Style.ForeColor = Color.Red;
//row.Cells["RESULTS"].Style.ForeColor = Color.Red;
}
}
As you are adding a new column to the datatable table, you need to bind the table to the datagridview (refer this : how to bind datatable to datagridview in c#) and then try to change the color.
Try this
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.ForeColor = Color.Red; //change the color to what you need
}
UPDATE : To iterate through the DataGridView and check for cell contents in a specific column, you need something like
foreach(DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[7].Value.ToString() == "BAD")
row.Cells[7].Style.ForeColor = Color.Red;
//row.Cells["RESULTS"].Style.ForeColor = Color.Red;
}
You need to place this piece of code inside an event that is triggered or function that is called after the DataGridView is populated with data.
Here is some sample code demonstrating the desired result
ASPX:
<asp:GridView ID="GridView1" runat="server" OnRowDataBound="GridView1_RowDataBound" AutoGenerateColumns="true">
</asp:GridView>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ArrayList al = new ArrayList();
al.Add("open"); al.Add("close"); al.Add("other"); al.Add("open"); al.Add("other"); al.Add("close"); al.Add("open");
this.GridView1.DataSource = al;
this.GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.Cells[0].Text == "open")
{
e.Row.Cells[0].ForeColor = System.Drawing.Color.Red;
}
else if (e.Row.Cells[0].Text == "close")
{
e.Row.Cells[0].ForeColor = System.Drawing.Color.Black;
}
else
{
e.Row.Cells[0].ForeColor = System.Drawing.Color.Green;
}
}
}
I have a page with a gridview (actually two, but they are identical and the same thing happens with either).
New rows are added to the gridview from the footerrow via a link button.
When using the page to edit existing data, a strange thing happens. When I create the page in edit mode (i.e. to add/remove rows from an existing set of data in the table) the first time I try to add another row to the gridview, the IsPostBack is set to false and thus the gridviews re-initialise / rebind and my change is lost. The second and further time that I try to add rows, it works fine as the PostBack is recognised.
What could be causing the PostBack not to be recognised as one?
I'm not sure it's worth posting code but I will post my Page_Load for what it is worth:
querystring:
a=n is "new" (for creating a page to add a new set of records)
a=e is "edit" (populate page with existing data to allow for adding / removing rows.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
String action = Request.QueryString["a"];
if (action == "n")
{
BindBuyGrid("create");
BindSellGrid("create");
}
else if(action == "e")
{
PopulatePage();
}
}
}
Update 1
protected void gvwBuyConditions_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "InsertNew")
{
AddNewRowToBuyConditionsGrid();
}
}
Update 2
The link button code. Surely this should trigger a postback?
<FooterTemplate>
<asp:LinkButton
ID="lnkInsert"
runat="server"
CommandName="InsertNew"
ToolTip="Add New Entry to List" >
<img src="../Images/Add.ico" height="20" width="20"/></asp:LinkButton>
</FooterTemplate>
Update 3
The AddNewRowToBuyConditionsGrid code:
private void AddNewRowToBuyConditionsGrid()
{
if (ViewState["BuyConditions"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["BuyConditions"];
DataRow drCurrentRow;
GridViewRow row = gvwBuyConditions.FooterRow;
DropDownList ddlSelectedCondition = row.FindControl("ddlConditionNew") as DropDownList;
try
{
if (ddlSelectedCondition.Text != "Select a Buy Condition")
{
drCurrentRow = dtCurrentTable.NewRow();
drCurrentRow["ConditionName"] = ddlSelectedCondition.SelectedItem.Text;
drCurrentRow["ConditionID"] = Convert.ToInt32(ddlSelectedCondition.SelectedItem.Value);
dtCurrentTable.Rows.Add(drCurrentRow);
drCurrentRow = null;
}
// take out the dummy "Select a Condition"
DataRow drtodie = dtCurrentTable.Rows.Find(-1);
if (drtodie != null)
{
dtCurrentTable.Rows.Find(-1).Delete();
}
//Store the current data to ViewState
ViewState["BuyConditions"] = dtCurrentTable;
//Rebind the Grid with the current data
gvwBuyConditions.DataSource = dtCurrentTable;
gvwBuyConditions.DataBind();
}
catch (Exception)
{
if (ddlSelectedCondition.SelectedItem.Value == String.Empty)
{
lblBuyMessage.Text = "Please select a Buy Condition.";
}
else
{
lblBuyMessage.Text = "That condition already exists in the list. Please select another condition.";
}
}
}
else
{
Response.Write("ViewState is null");
}
}
Update 4
Code on previous page that calls this page. e is just configured in string. Is it maybe the Server.Transfer?
protected void gvwStrategyList_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "UseEditForm")
{
//row index
int index = Convert.ToInt32(e.CommandArgument);
//retrieve StrategyID
int StrategyID = Convert.ToInt32(gvwStrategyList.DataKeys[index].Value);
Server.Transfer("~/AddStrategy.aspx?a=e&z=" + StrategyID, true);
}
}
I have a method called BindItems() and this method gets the values to a DataTable and then a GridView is bound to it.
Then I have an itemtemplate in that gridview which contains a drop down, this drop down gets populated from 1 -14 from code behind under Gridview_RowDataBound, now I need to figure a way to get the Quantity value in the DataTable on the other function "BindItems()" and for each Row in the gridview so a SelectedValue = datatable["Quantity"] or something.. how can I do this?
protected void BinItems(int myId)
{
//this data table contains a value "Quantity"
DataTable dt = MyClass.getItems(myId);
uxGrid.DataSource = dt;
uxGrid.DataBind();
}
protected void Gridview1_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType.Equals(DataControlRowType.DataRow))
{
DropDownList Myddl = e.Row.FindControl("MyQuantity") as DropDownList;
if (Myddl != null)
{
for (int i = 1; i < 15; i++)
{
Myddl.Items.Add(i.ToString());
}
}
}
//Some how i need to do a SelectedValue = datatable where field = Quantity for each row
}
You need to access the current-being-bound-row's DataItem, which in your case, is a DataRowView (since you are binding to a DataTable):
protected void Gridview1_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType.Equals(DataControlRowType.DataRow))
{
DropDownList Myddl = e.Row.FindControl("MyQuantity") as DropDownList;
if (Myddl != null)
{
for (int i = 1; i < 15; i++)
{
Myddl.Items.Add(i.ToString());
}
}
}
//here goes the "magic"
DataRowView dRow = e.Row.DataItem as DataRowView;
if(dRow != null)
{
Myddl.SelectedValue = dRow["Quantity"].ToString();
}
}
you should outside the DataTable dt and then youll be able to access it in the Function