I'm trying to retrieve the value of a DataGridViewComboBoxCell in the following way
When adding items to the ComboBox:
public void LoadLayouts()
{
ImmutableSet<string> layoutNames = _store.Current.Keys;
var dgvComboBox = (DataGridViewComboBoxColumn)this.schedulesDataGrid.Columns[1];
foreach (string name in layoutNames)
{
dgvComboBox.Items.Add(name);
}
}
When trying to read back the value:
var combo = (DataGridViewComboBoxCell) this.schedulesDataGrid[args.ColumnIndex, args.RowIndex];
string LayoutChosen = (string)combo.Value;
However, even if I can see that there is a value selected in the ComboBox, the Value comes back as null, and the FormattedValue comes back as "".
I've tried just setting the array of names as my DataSource, but then I'm not sure what to set for my Display and Value Members, considering I only have a single value (the name of the layout)
Thoughts?
At the time you attempt to read the cell's value, the row has not committed changes. If you have row headers visible, you will see the pencil icon on the row that has not been committed. This normally happens after the cell looses focus. You can force the issue by hooking into the in-place editing control combo-box and causing it to post EndEdit when it changes values:
void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
if (comboBox != null)
{
// remove any handler we may have added previously
comboBox.SelectionChangeCommitted -= new EventHandler(comboBox_SelectionChangeCommitted);
// add handler
comboBox.SelectionChangeCommitted += new EventHandler(comboBox_SelectionChangeCommitted);
}
}
void comboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
// Allow current dispatch to complete (combo-box submitting its value)
// then EndEdit to commit the change to the row
dgv.BeginInvoke(new Action(() => dgv.EndEdit()));
}
Related
I have a View Model in which my data is stored to be used on the presenter and window. However, I now need to get (when pressing a button) the current row's results on the grid into my view model. I first used the mouse double click event, but the requirements changed from that to a button on the form:
private void dgvResults_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (this.colOrderNo.Index != e.ColumnIndex || e.RowIndex < 0) return;
var auditOrder = (PurchaseOrdersTrackingViewModel) this.dgvResults.Rows[e.RowIndex].DataBoundItem;
this.AuditOrderKey = $"{auditOrder.OrderNo}|{auditOrder.ItemNo}|{auditOrder.WarehouseId}|{auditOrder.ItemSequence}";
}
That's my old code. Now I need that here:
private void btnAuditLog_Click(object sender, EventArgs e)
Not sure how to refer to the RowIndex without the DataGridViewCellMouseEventArges event. I tried the CurrentRow property, but it doesn't do the job.
Just another question on the fly, if someone could assist with that as well, how do I get a value from one form to another, spesifically a properties value. It's not on the grid, in a control. It's basically just public string order that's all. I set the value on one form, then need it for query filtering on another. Let me know if you need anything else.
You want to use the SelectedRows property of the DataGridView. It tells which row is selected. In this case, you seem to want the first selected row (since you have a single property called this.AuditOrderKey).
The column order no to longer matters in this context.
if (dgvResults.SelectedRows.Count == 0) return;
var auditOrder = (PurchaseOrdersTrackingViewModel) dgvResults.SelectedRows[0].DataBoundItem;
this.AuditOrderKey = $"{auditOrder.OrderNo}|{auditOrder.ItemNo}|{auditOrder.WarehouseId}|{auditOrder.ItemSequence}";
If you don't have selected rows, CurrentRow is an option:
if (dgvResults.CurrentRow == null) return;
var auditOrder = (PurchaseOrdersTrackingViewModel) dgvResults.CurrentRow.DataBoundItem;
this.AuditOrderKey = $"{auditOrder.OrderNo}|{auditOrder.ItemNo}|{auditOrder.WarehouseId}|{auditOrder.ItemSequence}";
Use the SelectedRows property of the DataGridView. Assuming that you set your DataGridView as MultiSelect = false; and SelectionMode = FullRowSelect;
if (dgvResults.SelectedRows.Count > 0)
{
dgvResults.SelectedRows[0].Cells["yourColumnName"].Value.ToString();
}
In your button click event, it will look like this. (Assuming that your button name is btnEdit)
private void btnEdit_Click(object sender, EventArgs e)
{
if (dgvResults.SelectedRows.Count > 0)
{
string selectedValue = dgvResults.SelectedRows[0].Cells["yourColumnName"].Value.ToString();
}
}
I'm new to c# and I'm now learning how to trigger events based on some form actions.
This is part of view:
private void comboGoodsName_TextChanged(object sender, EventArgs e)
{
controller.selectName(comboGoodsName.Text);
}
public void nameChanged(object sender, MeasurementEventArgs e)
{
comboGoodsName.TextChanged -= comboGoodsName_TextChanged;
comboGoodsName.Text = e.value;
comboGoodsName.TextChanged += comboGoodsName_TextChanged;
}
And this is part of controller:
public void selectName(string name)
{
model.Name = name.Split('|')[0].Trim();
if (name.Contains(" | "))
{
string code = name.Split('|')[1].Trim();
model.NameCode = code;
}
}
The scenario is as follows:
I want to have a ComboBox with some items in it (doesn't matter what's the source). Items are combination of name and code in following format: NAME | CODE. When I enter some text in ComboBox (type it in), comboGoodsName_TextChanged is triggered, which in turn calls selectName which sets model's property, which in turn raises an event which is observed by nameChanged. This works fine, as expected (puts NAME in ComboBox and CODE to TextBox - not shown as not relevant). Problem shows up when I select item from ComboBox drop-down list. When I select item, instead of showing NAME in ComboBox, I see NAME | CODE.
Edit: In the model, property is set correctly, which I confirmed by printing its value. So, issue is related only to displaying proper value in ComboBox.
Try this:
private void comboGoodsName_SelectedIndexChanged(object sender, EventArgs e)
{
// if combobox has selected item then continue
if (comboGoodsName.SelectedIndex > -1)
{
// split the selecteditem text on the pipe into a string array then pull the first element in the array i.e. NAME
string nameOnly = comboGoodsName.GetItemText(this.comboGoodsName.SelectedItem).Split('|')[0];
// handing off the reset of the combobox selected value to a delegate method - using methodinvoker on the forms main thread is an efficient to do this
// see https://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker(v=vs.110).aspx
this.BeginInvoke((MethodInvoker)delegate { this.comboGoodsName.Text = nameOnly; });
}
}
I have gridcontrol that has a RepositoryLookupEdit in one of the columns. I can get the value of RepositoryLookupEdit after changed, but I dont know how to get the which row's RepositoryLookupEdit value changed. How can I get the Row ID?
With the code below, I can get the RepositoryLookupEdit value.
private void repositoryItemLookUpEdit1_EditValueChanged(object sender, EventArgs e)
{
LookUpEdit edit = sender as LookUpEdit;
var row = edit.Properties.GetDataSourceRowByKeyValue(edit.EditValue);
}
Since repositoryItemLookUpEdit isn't restricted to GridControls you cannot get the row handle from this event. You however have other possibilities.
First, if the edit is done by the user, you can use the ColumnView.GetFocusedRow() method to get the current grid row.
If however the edit value is changed via code it will also be changed in the grid so you can now use the ColumnView.CellValueChanged event.
private void repositoryItemLookUpEdit1_EditValueChanged(object sender, EventArgs e)
{
LookUpEdit edit = sender as LookUpEdit;
var row = edit.Properties.GetDataSourceRowByKeyValue(edit.EditValue);
gridRow = gridView.GetFocusedRow() as MyDataRow
}
What I want to do is to change value of row's forth cell if cell number 3 is changed. I have an EditEnding method for my grid. That's my method below. I don't really know how to finish it
that's the grid definition:
<DataGrid x:Name="dataGrid1"... CellEditEnding="dataGrid1_EditEnding">
and the method:
private void dataGrid1_EditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
// initializing DataRowView from my datagrid
DataRowView drv = (DataRowView)dataGrid1.CurrentItem;
// checking if there were any changes
if (drv.Row[3, DataRowVersion.Original] != drv.Row[3])
{
//set value to cell
}
}
Well, i did my stuff, just forget to post it here.
First I did it with EditEnding event, it looked like that:
private void dataGrid1_EditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
DataRowView drv = (DataRowView)dataGrid1.CurrentItem;
if (drv.Row[3, DataRowVersion.Original] != drv.Row[3])
{
rowView.Row.SetField(4, /* my logic here */);
}
}
The problem was it was adding the value only on second edit. Then I changed my idea and added a RowChanged event to my DataTable, which was like that:
static void dtSP_RowChanged(object sender, DataRowChangeEventArgs e)
{
bool temp = false;
try
{
temp = e.Row[4, DataRowVersion.Original] == e.Row[4];
}
catch { }
if (temp && int.Parse(e.Row[3].ToString()) != -1)
{
e.Row[4] = (/* my logic */);
}
}
The method was going into infinity loop (it was noticing, that fourth row had changed).
And then i saw this:
http://www.windowsdevcenter.com/pub/a/dotnet/2003/05/26/datacolumn_expressions.html
I've ended with one line long code:
dtSP.Columns[4].Expression = "expression";
#blindmeis, I forgott to mention I use ADO.NET, sorry
do not edit the datagridrow - edit the underlying object in wpf!
this mean when the bound property to cell 3 is changed then do your changes to the property bound to cell 4. INotifyPropertyChanged will notify your grid and will show your changes
If you already have logic to calculate cell4 value when cell3 is changed, then when property binded to column 3 is changed you should call INotifyPropertyChanged of property binded to column 3 & 4.
Background
When I hit a button on a WinForm, I am loading data into a BindingSource that serves as the data source for a DataGridView. Once the data is loaded, I go through and make some modifications to the DataGridView; in particular, I 1) set any cells that are valued as DBNull to the string value "NULL", 2) italicize the same cells, and 3) highlight some rows.
Simple example of what I'm doing:
private void btnFetch_Click(object sender, EventArgs e)
{
// If there's already a DataSource, Dispose of it.
if (bsMessageTracking.DataSource != null)
{
(bsMessageTracking.DataSource as DataTable).Dispose();
}
// Get new DataSource.
bsMessageTracking.DataSource = GetDataTable(); // Details not relevant.
// Show NULL values.
foreach (DataGridViewRow row in dgv.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.Value is DBNull)
{
cell.Value = "NULL";
cell.Style.Font = new Font(dgv.DefaultCellStyle.Font, FontStyle.Italic);
}
}
}
// Apply highlighting.
foreach (DataGridViewRow row in dgvMessageTracking.Rows)
{
if (HighlightRow(row)) // Details not relevant.
{
row.DefaultCellStyle.BackColor = Color.LightYellow;
}
}
}
The data gets loaded based on input into a TextBox on the form.
Situation
Everything works great if this occurs on the button click. However, in order to provide some convenience to the user, I am allowing this form to get loaded with data prepopulated - the main form will instantiate this form with the data to put into the TextBox, and this btnFetch_Click handler will get called from the constructor:
internal MessageTracking(string ID)
{
InitializeComponent();
// Setup data source.
dgvMessageTracking.DataSource = bsMessageTracking;
// Set ID and run query.
if (ID != null)
{
// Set ID.
txtlID.Text = ID;
// Run!
btnFetch_Click(null, null);
}
}
The value of the cells gets changed (so I see NULL), but the font and the highlighting don't stick.
What I've tried
If I replicate the highlighting code in the OnShown method, the highlighting sticks. However, replicating the font code there doesn't work. I can make the font stick if I put it in CellFormatting, but that seems like overkill to me, because I only need this to be run once when the form is loaded - it works fine if the process is run after the form is visible.
Plea
If anyone has any suggestions, I would appreciate them. Thanks!
For the event handler you are using I would suggest using the dataGridView Cell_Formatting like #zimdanen. However, here is how I made it work.
private void small8PtToolStripMenuItem_Click(object sender, EventArgs e)
{
fontSize = 8;
dataGridBatchHistory.Refresh();
}
fontSize is an integer I used to set the font dynamically and you can set most properties this way. than i would call my CellFormatting function
private void dataGridBatchHistory_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
e.CellStyle.Font = new Font("Tahoma", fontSize);
}
this would update my form with the new correct size upon clicking my toolstrip menu item. however i believe this works for many of the events you can create!
I guess, from the lack of responses, that there is no better way if you want the formatting shown when the form first becomes visible. I have removed the Show NULL values portion of the btnFetch_Click handler and added this dgvMessageTracking_CellFormatting handler to handle this functionality at all times:
private void dgvMessageTracking_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.Value is DBNull)
{
e.Value = "NULL";
e.CellStyle.Font = new Font(dgvMessageTracking.DefaultCellStyle.Font, FontStyle.Italic);
}
}