Prevent BindingSource from adding two blank rows to gridview - c#

I have BindingSource that attached to grid control like this
private BindingSource listDepartmentDto = new();
private async Task LoadDataAsync()
{
listDepartmentDto.DataSource = await departmentService.GetAllDepartmentsAsync();
gridControl1.DataSource = listDepartmentDto;
}
And I binding Controls like this
private void BindingControls()
{
var departmentDto = listDepartmentDto.Current as DepartmentDto;
txtID.DataBindings.Add(new Binding("EditValue", listDepartmentDto, nameof(departmentDto.IdDepartment)));
txtTitle.DataBindings.Add(new Binding("EditValue", listDepartmentDto, nameof(departmentDto.NameDepartment)));
txtDescription.DataBindings.Add(new Binding("EditValue", listDepartmentDto, nameof(departmentDto.DescriptionDepartment)));
}
And I use CurrentChanged event like this
listDepartmentDto.CurrentChanged += new EventHandler(listDepartmentDtoChanged);
private void listDepartmentDtoChanged(object sender,EventArgs e)
{
var departmentDto = listDepartmentDto.Current as DepartmentDto;
if (departmentDto.IdDepartment == 0)
{
btnSave.Text = Resources.Save;
btnNew.Enabled = false;
btnDelete.Enabled = false;
txtTitle.Focus();
return;
}
btnSave.Text = Resources.Edit;
btnNew.Enabled = true;
btnDelete.Enabled = true;
}
And in btnNew click event like this
private async void btnNew_Click(object sender, EventArgs e)
{
listDepartmentDto.AddNew();
await Permission();
}
The problem is when I click on btnNew it create blank row and when I select an other row and click again on btnNew it create new blank row and so on.
How can I prevent this behavior? and if the user move to an other row without entry any data the row removed automatically
The grid view edtiable has set to false.
the grid view (add,remove) row has set to false.

Related

ComboBox SelectedIndexChanged always fired/triggered even disabled

I got two comboxBox with SelectedIndexChanged event enabled.
In the comboBox2 i want to change the SelectedValue of comboBox1, and that works, but the SelectedIndexChanged of comboBox1 is always triggered even i explicit disabled that.
And the code in selectedIndexChange of the ComboBox1 overwrite what I do in the ComboBox2, that the problem.
I've tried hundreds ways to avoid that but anything works, the event always occurs.
Bellow is my code of ComboBox1:
private void cmbBeneficiario_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (!cb.Focused)
{
return;
}
systemChange = true;
if (cnpjChange)
{
if (!string.IsNullOrWhiteSpace(cmbBeneficiario.Text) &&
!string.IsNullOrWhiteSpace(cmbBeneficiario.Text))
{
var beneficiarioApoliceBeneficiario =
averbacaoController.GetApoliceBeneficiario(cmbBeneficiario.Text);
var apolices = beneficiarioApoliceBeneficiario.Select(x => x.numero_apolice).ToList();
cmbApolice.DataSource = apolices;
cmbApolice.DisplayMember = "numero_apolice";
cmbApolice.Invalidate();
Refresh();
cmbApolice_SelectedIndexChanged(this, e);
var listBene = beneficiariosList;
var filteredList = listBene.Where(x => x.nome_beneficiario == cmbBeneficiario.Text).ToList();
cbbCNPJBeneAverb.DisplayMember = "cnpj_beneficiario";
cbbCNPJBeneAverb.DataSource = filteredList;
}
CarregaBeneficiarioPerfil();
systemChange = false;
}
}
The comboBox2 code (note that I disabled the event of combobox1):
private void cbbCNPJBeneAverb_SelectedIndexChanged(object sender, EventArgs e)
{
cnpjChange = true;
ComboBox cb = (ComboBox)sender;
if (!cb.Focused)
{
return;
}
Console.WriteLine($#"Old ID {cmbBeneficiario.SelectedValue}");
var beneficiario = averbacaoController.GetBeneficarioByCNPJ(cbbCNPJBeneAverb.Text, cmbBeneficiario.Text);
cmbBeneficiario.SelectedIndexChanged -= new EventHandler(cmbBeneficiario_SelectedIndexChanged);
if (cbbCNPJBeneAverb.SelectedIndex > -1)
{
cmbBeneficiario.SelectedValue = beneficiario.id_beneficiario;
CarregaBeneficiarioPerfil();
}
Console.WriteLine($#"New ID {cmbBeneficiario.SelectedValue}");
Console.WriteLine($#"Tinha que ser o ID {beneficiario.id_beneficiario}");
cmbBeneficiario.SelectedIndexChanged += new EventHandler(cmbBeneficiario_SelectedIndexChanged);
cnpjChange = false;
}
Printscreen of my debug:
As my comments above, you can use a class-scope variable to do check:
Add a temporary class-scope variable:
private bool cb1EventIgnore = false;
Set it to ture/false in cbbCNPJBeneAverb_SelectedIndexChanged:
if (cbbCNPJBeneAverb.SelectedIndex > -1)
{
cb1EventIgnore = true;
cmbBeneficiario.SelectedValue = beneficiario.id_beneficiario;
CarregaBeneficiarioPerfil();
cb1EventIgnore = false;
}
Check the value cb1EventIgnore in cmbBeneficiario_SelectedIndexChanged at the beginning:
private void cmbBeneficiario_SelectedIndexChanged(object sender, EventArgs e)
{
if(cb1EventIgnore) return;
//your codes here
}
After a lot of attempts, bellow are the piece of code that solved my question:
cmbBeneficiario.Enabled = false;
Simple like this, i dont know why c# was not able to not trigger the event even I explicit told him to.

How to handle click event of two FlowLayoutPanel with some dynamically created controls?

I have two FlowLayoutPanel controls on the same form with some controls on both of them. What O want is that if FlowLayoutPanel1 controls are clicked, I want to change label1.Text and if FlowLayoutPanel2 controls are clicked, I want to change label2.Text.
Here is my code to add controls in both FlowLayoutPanel.
public void Load_DFlavours(FlowLayoutPanel FLP)
{
try
{
FLP.Controls.Clear();
using (SQLiteConnection con = new SQLiteConnection(AppSettings.ConnectionString()))
{
con.Open();
using (SQLiteDataAdapter sda = new SQLiteDataAdapter("Select distinct(Flavour_Name) From Flavours Where Category_Name = 'Flavours' Order By Flavour_Name", con))
{
DataTable dt = new DataTable();
sda.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
RadioButton rb2 = new RadioButton();
rb2.AutoSize = true;
rb2.Font = new Font("Segoe UI Semilight", 10F);
rb2.Margin = new Padding(2);
rb2.Text = dr["Flavour_Name"].ToString();
rb2.UseVisualStyleBackColor = true;
rb2.Tag = dr["Flavour_Name"].ToString();
FLP.Controls.Add(rb2);
rb2.CheckedChanged += Rb2_CheckedChanged;
}
}
con.Close();
}
}
catch (SQLiteException se)
{
MessageBox.Show(se.Message);
}
}
Clickevent Code:
private void Rb2_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb2 = (RadioButton)sender;
string flavour = rb2.Tag.ToString();
//I want to do something here if flowlayoutPanel 1 control is
clicked change the label1.Text and if flowlayoutPanel 2 control is
clicked change the label2.text
//I have tried this
if(rb2.Checked)
{
label1.text = flavour;
}
}
How to know which FlowLayoutPanel Controls are clicked?
I can do this by creating multiple methods but I want to do this work on the same method.
For more clarification, see this image:
Don't have a computer to check right now, but I assume this should work
if (rb2.Checked)
{
if (rb2.Parent.Name == "flowlayoutPanel1")
{
label1.Text = flavour;
}
else if (rb2.Parent.Name == "flowlayoutPanel2")
{
label2.Text= flavour;
}
}
You can add more information to Tag property of the RadioButton. For example, you can:
rb2.Tag = $"{dr["Flavour_Name"]}|{FLP.Name}";
This way, you can use string.Split() to take the Flavour_name and FlowLayoutPanel name. But since the Tag property accept object, you can create new class to hold the information.
Using this approach, you can use:
RadioButton rb2 = (RadioButton)sender;
string[] splits = rb2.Tag.ToString().Split('|');
string flavour = splits[0];
string flowPanelName = splits[1];
You can use the ControlAdded and ControlRemoved events of the FlowLayoutPanel to subscribe/unsubscribe to an event which changes the text of the label based on the clicked control:
private void flowLayoutPanel1_ControlAdded(object sender, ControlEventArgs e)
{
e.Control.Click += flowLayoutPanel1_ControlClicked;
}
private void flowLayoutPanel1_ControlRemoved(object sender, ControlEventArgs e)
{
e.Control.Click -= flowLayoutPanel1_ControlClicked;
}
private void flowLayoutPanel1_ControlClicked(object sender, EventArgs e)
{
var control = (Control)sender;
label1.Text = control.Text;
}
private void flowLayoutPanel2_ControlAdded(object sender, ControlEventArgs e)
{
e.Control.Click += flowLayoutPanel2_ControlClicked;
}
private void flowLayoutPanel2_ControlRemoved(object sender, ControlEventArgs e)
{
e.Control.Click -= flowLayoutPanel2_ControlClicked;
}
private void flowLayoutPanel2_ControlClicked(object sender, EventArgs e)
{
var control = (Control)sender;
label2.Text = control.Text;
}
And of course, you need to subscribe to these events first, either by selecting the event from the properties window, or by calling the following:
flowLayoutPanel1.ControlAdded += flowLayoutPanel1_ControlAdded;
flowLayoutPanel1.ControlRemoved += flowLayoutPanel1_ControlRemoved;
flowLayoutPanel2.ControlAdded += flowLayoutPanel2_ControlAdded;
flowLayoutPanel2.ControlRemoved += flowLayoutPanel2_ControlRemoved;

ASP.NET Textbox losing values after postback which were set during editing

There's a gridview in my program whose row's data is to be loaded in textboxes if edit is clicked.
Here is the code where I'm filling the data in textboxes after edit is clicked
protected void GV_Parameters_RowEditing(object sender, GridViewEditEventArgs e)
{
GV_Parameters.EditIndex = e.NewEditIndex;
int index = e.NewEditIndex;
IsEditing = true;
Label lbl_frmdate = (Label)GV_Parameters.Rows[index].FindControl("lbl_frmdate") as Label;
Label lbl_todate = (Label)GV_Parameters.Rows[index].FindControl("lbl_todate") as Label;
EditFromDate = lbl_frmdate.Text.ToUpper();
lbl_frm_edit.Text = EditFromDate;
EditToDate = lbl_todate.Text.ToUpper();
lbl_to_edit.Text = EditToDate;
Label lbl = (Label)GV_Parameters.Rows[index].Cells[3].FindControl("lbl_Is_holiday");
string is_holiday = lbl.Text;
Label lbl_std_intime = (Label)GV_Parameters.Rows[index].FindControl("lbl_std_intime") as Label;
Label lbl_std_outtime = (Label)GV_Parameters.Rows[index].FindControl("lbl_std_outtime") as Label;
string[] arr_std_intime;
string[] arr_std_outtime;
if (is_holiday != "1")//working day
{
r_work_holiday.SelectedIndex = 0;
IsHoliday = false;
if (lbl_std_intime.Text != "")
{
arr_std_intime = lbl_std_intime.Text.Split(':');
txt_std_TimeInHours.Text = arr_std_intime[0].ToString();
txt_std_TimeInMins.Text = arr_std_intime[1].ToString();
}
if (lbl_std_outtime.Text != "")
{
arr_std_outtime = lbl_std_outtime.Text.Split(':');
txt_std_TimeOutHours.Text = arr_std_outtime[0].ToString();
txt_std_TimeOutMins.Text = arr_std_outtime[1].ToString();
}
}
else
{
IsHoliday = true;
//r_workingday.Checked = false;
//r_holiday.Checked = true;
r_work_holiday.SelectedIndex = 1;
Label lbl_remarks = (Label)GV_Parameters.Rows[index].FindControl("lbl_remarks") as Label;
txt_holiday_desc.Text = lbl_remarks.Text;
}
collapse_state = "expand";
}
There is a radiobutton list who shows the edited row is holiday or working day,
if user changes the selection in radioButtonList, PostBack occurs and this is the time when all of the texboxes turn blank.
protected void r_work_holiday_SelectedIndexChanged(object sender, EventArgs e)
{
if(r_work_holiday.SelectedIndex==0)
{
IsHoliday = false;
}
else
{
IsHoliday = true;
}
collapse_state = "expand";
}
There's no any method in page load who is clearing the textboxes.
protected void Page_Load(object sender, EventArgs e)
{
if (IsEditing)
{
collapse_state = "expand";
}
if (!Page.IsPostBack)
{
BindYears();
}
}
Please help
Update ::
lbl_frm_edit and lbl_to_edit are not getting reset after postback.
The variable EditFromDate and EditToDate are being set by Viewstate
It's been sometime I worked in ASP controls but if I remember correctly, the content in textboxes are generally cleared on every post back by ASP .NET. The state of the textboxes are not saved.
Here is an answer I found while researching this issue.
You could store the value of the textboxes in ViewState and assign them back on the PageLoad event. Something like
txt_std_TimeOutHours.Text = arr_std_outtime[0].ToString();
txt_std_TimeOutMins.Text = arr_std_outtime[1].ToString();
ViewState["TimeOutHours"] = arr_std_outtime[0].ToString();
ViewState["TimeOutMins"] = arr_std_outtime[1].ToString();
And on the PageLoad event you can do this to restore the values.
if(Page.IsPostBack)
{
txt_std_TimeOutHours.Text = ViewState["TimeOutHours"].ToString();
txt_std_TimeOutMins.Text = ViewState["TimeOutMins"].ToString();
}
Hope this helps!

LookUpEdit does not work

I have XtraTabControl with two pages, both of them has one LookUpEdit,
when page load which on the secondpage does not work,
void Frm1_Load(object sender, EventArgs e)
{
lookUpEditA.Properties.DataSource = datasource. . . . .
lookUpEditA.Properties.ValueMember = "ID";
lookUpEditA.Properties.DisplayMember = "xxxx";
lookUpEditA.Properties.PopulateColumns();
lookUpEditA.Properties.Columns["ID"].Visible = false;
lookUpEditB.Properties.DataSource = datasource. . . . .
lookUpEditB.Properties.ValueMember = "ID";
lookUpEditB.Properties.DisplayMember = "xxxx";
lookUpEditB.Properties.PopulateColumns();
lookUpEditB.Properties.Columns["ID"].Visible = false;
}
I can see the issue only with setting visibility of 'ID' column on second LookUpEdit.
The reason of this issue is that the LookUpEdit can't operate with datasource representation (perform populating columns, operating with column's visibility and etc.) until it's handle been created. The second LookUpEdit will create it's handle only when the second tab page has been shown.
To avoid the issue you can use the following approach:
if(!lookUpEditB.IsHandleCreated)
lookUpEditB.HandleCreated += lookUpEditB_HandleCreated;
else InitLookUpEditDataSource();
//...
void lookUpEditB_HandleCreated(object sender, EventArgs e) {
lookUpEditB.HandleCreated -= lookUpEditB_HandleCreated;
InitLookUpEditDataSource();
}
void InitLookUpEditDataSource() {
lookUpEditB.Properties.DataSource = this.categoriesBindingSource;
lookUpEditB.Properties.DisplayMember = "CategoryName";
lookUpEditB.Properties.ValueMember = "CategoryID";
lookUpEditB.Properties.PopulateColumns();
lookUpEditB.Properties.Columns["CategoryID"].Visible = false;
}
As #DmitryG said, you can not use lookUpEditB.Properties.PopulateColumns() statement until control's UI handlers are not created.
As per my understanding these are created only when the second tab page shown. Except creating conditional statement to create handlers etc, you can use the XtraTabControl.SelectedPageChanged Event where you can bind the data source of the lookUpEditB by checking condition that XtraTabControl.SelectedTabPage Property is set with Page2 which contain the lookUpEditB.
Check the tested Code Snippet below:
public partial class TabControlTest : Form
{
List<Category> dataSource = new List<Category>();
public TabControlTest()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
dataSource.Add(new Category { ID = i + 1, Name = "Category" + (i + 1) });
}
}
private void TabControlTest_Load(object sender, EventArgs e)
{
lookUpEditA.Properties.DataSource = dataSource;
lookUpEditA.Properties.ValueMember = "ID";
lookUpEditA.Properties.DisplayMember = "Name";
lookUpEditA.Properties.PopulateColumns();
lookUpEditA.Properties.Columns["ID"].Visible = false;
}
private void xtraTabControl1_SelectedPageChanged(object sender, DevExpress.XtraTab.TabPageChangedEventArgs e)
{
if (xtraTabControl1.SelectedTabPage == xtraTabPage2)
{
lookUpEditB.Properties.DataSource = dataSource;
lookUpEditB.Properties.ValueMember = "ID";
lookUpEditB.Properties.DisplayMember = "Name";
lookUpEditB.Properties.PopulateColumns();
lookUpEditB.Properties.Columns["ID"].Visible = false;
}
}
}
Hope this help.

I want to programmatically generate a click on a DataGridView Row in C#

I have a DataGridView in a form and I want to programmatically click its first row. I have found code to select its rows or columns from code.
For eg.
datagridview.Columns[0].Selected = true;
datagridview.Rows[0].Selected = true;
However this code is not raising the click event on the datagridview. If any one has coded how to click a datagridview from code, please extend your kind help.
Simply call the event handler method e.g.:
datagridviewRowClickedEventHandler(new object(), new eventargs());
If you use the sender or e parameters in the event handler then you will need to work out how to pass in the correct values.
Insert the follwing code into your project where appropriate (Usually on the form which has the datagridview).
Make sure to change the name of the DataGridView from dataGridView1 to the appropriate one on your form.
private void Form1_Load(object sender, EventArgs e)
{
//call the cell click event with the first cell as the parameters.
dataGridView1_CellClick(dataGridView1, new DataGridViewCellEventArgs(0, 0));
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
//put your code for handling cell click here
}
It looks like you have the first half, setting the propers rows Selected value to true. Now you can programatically call the row click handler and it should proceed as if you had clicked it within the GUI.
datagridview.Columns[0].Selected = true;
datagridview.Rows[0].Selected = true;
It makes look the row like selected but it won't change dataGridView.CurrentRow. So it could be an issue.
dataGridView.CurrentCell = dataGridView[<column>, <row>];
will change CurrentRow value too.
Hope it will help.
I assume you want to apply DataSource and select the first row? Right?
The best way to do it like this
private async void DgvAreas_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
}
And here is the code to simulate click on row.
DgvAreas_RowStateChanged(dgvAreas, new DataGridViewRowStateChangedEventArgs(dgvAreas.Rows[0], DataGridViewElementStates.Selected));
In my case I have 3 DataGridViews so I populate the first one easly.
The second one I populate when user click the first DataGridView and in this case I use DgvStaff_RowStateChanged event.
And in this event DgvStaff_RowStateChanged I have the code to get data async and populate the third DataGridView and after I apply data source for the second DataGridView I need to get data for the first row of this view and display it in the third DataGridView. It is cascade logic.
private async void DgvStaff_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
try
{
// For any other operation except, StateChanged, do nothing
if (e.StateChanged != DataGridViewElementStates.Selected) return;
if (sender is MetroFramework.Controls.MetroGrid)
{
if ((sender as MetroFramework.Controls.MetroGrid).SelectedRows.Count > 0)
{
dgvGeoData.DataSource = null;
dgvAreas.DataSource = null;
metroProgressSpinnerMain.Visible = true;
panelFilter.Enabled = false;
dgvAreas.RowStateChanged -= DgvAreas_RowStateChanged;
var selectedRow = (sender as MetroFramework.Controls.MetroGrid).SelectedRows[0];
var machineModelShortView = (MachineModelShortView)selectedRow.DataBoundItem;
var startTime = Convert.ToDateTime(dateTimePickerStart.Value.ToShortDateString());
var endTime = Convert.ToDateTime(metroDateTimeEnd.Value.ToShortDateString());
var areas = await UpdateAreaItems(machineModelShortView.MachineID, startTime, endTime);
if (areas.Any())
{
BeginInvoke((Action)(() =>
{
dgvAreas.DataSource = areas.OrderBy(x => x.AreaID).ThenBy(x => x.TimeStart).ToList();
dgvAreas.RowStateChanged += DgvAreas_RowStateChanged;
// !!! This is how you simulate click to the FIRST ROW dgvAreas.Rows[0]
DgvAreas_RowStateChanged(dgvAreas,
new DataGridViewRowStateChangedEventArgs(dgvAreas.Rows[0], DataGridViewElementStates.Selected));
metroProgressSpinnerMain.Visible = false;
panelFilter.Enabled = true;
}));
}
else
{
BeginInvoke((Action)(() =>
{
metroProgressSpinnerMain.Visible = false;
panelFilter.Enabled = true;
}));
}
}
}
}
catch (Exception ex)
{
logger.Error(ex);
}
}
And here
private async void DgvAreas_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
try
{
// For any other operation except, StateChanged, do nothing
if (e.StateChanged != DataGridViewElementStates.Selected) return;
//Get GeoData
if (sender is MetroFramework.Controls.MetroGrid)
{
if ((sender as MetroFramework.Controls.MetroGrid).SelectedRows.Count > 0)
{
dgvGeoData.DataSource = null;
metroProgressSpinnerMain.Visible = true;
panelFilter.Enabled = false;
var selectedRow = (sender as MetroFramework.Controls.MetroGrid).SelectedRows[0];
var areaItem = (AreaItem)selectedRow.DataBoundItem;
var geoData = await UpdateWDataPositionItems(areaItem.MachineID, areaItem.TimeStart, areaItem.TimeEnd.Value);
if (geoData.Any())
{
BeginInvoke((Action)(() =>
{
dgvGeoData.DataSource = geoData.OrderBy(x => x.AtTime).ToList();
metroProgressSpinnerMain.Visible = false;
panelFilter.Enabled = true;
}));
}
else
{
BeginInvoke((Action)(() =>
{
metroProgressSpinnerMain.Visible = false;
panelFilter.Enabled = true;
}));
}
}
}
}
catch (Exception ex)
{
logger.Error(ex);
}
}

Categories