I have a gridcontrol which is binded to a list using a BindingSource.
invoice_GroupListBindingSource.Datasource= _list.
GridControl.DataSource = invoice_GroupListBindingSource
Now there is one checkedit column (let's call it Invoice_Bool). The functionality requirement is when user select anyone of he column all the datarows should be updated and select column for them should also be selected.
Foloowing is the code I tried:
private void invoice_GroupListBindingSource_CurrentItemChanged(object sender, EventArgs e)
{
Data.InvoiceGroupList.InvoiceGroupInfo current;
if (invoice_GroupListBindingSource.Current == null)
{
current = null;
}
else
{
current = ((Data.InvoiceGroupList.InvoiceGroupInfo)invoice_GroupListBindingSource.Current);
}
if (current.Invoice_Bool)
{
foreach (var item in _invoice_list)
{
item.Invoice_Bool = true;
}
this.invoice_GroupListBindingSource.DataSource = _invoice_list;
}
}
With this I am getting an updated list with all the Invoice_Bool true when user selects any of them (as required), however in the front-end(in the grid) all the bool values are still unselected. Any idea how to update the grid also when data source changes.. ideally it should be done automatically but I am not sure why it is not updating.
Related
I have a datagridview that when it loaded first row is selected. I want to delete a record but I don't want first row select. I want message to user that first select a row then click delete button. I try these code but they don't worked.
//kharidDataGridView.Rows[0].Selected = false;
//kharidDataGridView.ClearSelection();
//kharidDataGridView.CurrentCell = null;
I use below codes in WPF:
object item = datagrideview1.SelectedItem;
if (item == null)
{
//message to user
}
thank you
You can remove default selected row by handling data-grid loaded event
private void datagrideview1_Loaded(object sender, RoutedEventArgs e)
{
datagrideview1.SelectedIndex = -1;
}
private void dgGrid_CellListSelect(object sender, CellEventArgs e)
{
if (e.Cell.Column.Key == "ColumnA")
{
UltraGridRow selectedItem = ((UltraCombo)e.Cell.EditorControlResolved).SelectedRow;
if (selectedItem != null)
{
//Option A
cmbColumnB.DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
cmbColumnB.DataBind();
//Option B
//((UltraCombo)e.Cell.Row.Cells["ChipSetID"].EditorControlResolved).DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
}
}
}
There is a button that allow the datagrid to add new row.
This datagrid have 2 columns and both columns are UltraCombo. ColumnB combobox's dataSource will based on ColumnA. Based on the above code, it works if the datagrid only have 1 row, but once user add another row, both row's ColumnB will be sharing the same DataSource.
How to make sure ColumnB's DataSource stay independently without affecting other rows? It's very obvious that this happened because every row are sharing the same component which is cmbColumnB but I'm not sure on how to remove the reference
I've found the solution which is everytime create a new UltraCombo and bind it to the particular cell's EditorControl
private void dgGrid_CellListSelect(object sender, CellEventArgs e)
{
if (e.Cell.Column.Key == "ColumnA")
{
UltraGridRow selectedItem = ((UltraCombo)e.Cell.EditorControlResolved).SelectedRow;
if (selectedItem != null)
{
UltraCombo cmbValue = new UltraCombo();
cmbValue.LimitToList = true;
cmbValue.DropDownStyle = UltraComboStyle.DropDownList;
cmbValue.DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
cmbValue.ValueMember = someDS.someDT.someColumnIDColumn.ColumnName;
cmbValue.DisplayMember = someDS.someDT.someColumnDescriptionColumn.ColumnName;
cmbValue.BindingContext = someDg.BindingContext;
cmbValue.DataBind();
e.Cell.Row.Cells["ColumnB"].EditorControl = cmbValue;
e.Cell.Row.Cells["ColumnB"].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.DropDownList;
}
}
}
So I have a DataGridView which I am using as a “row selector” on a form, and a bunch of controls are bound to the bindingSource.
One of the bound controls is a ComboBox serving as a lookup which enables status choices for the rows, this is populated from a DataTable with data pulled from the DB.
The population of this box is without any issue.
When a given row is selected from the DGV the form controls display data from the given row as they should, however the “statusComboBox” is not quite playing the game.
If in the DGV, I choose a row that has a different status to one previously selected, it works as it should, however, if I choose a row with the same value to a previously selected row, instead of the box showing the DisplayMember it shows the ValueMember.
IT only seems to occur in the above scenario, where the rows selection only instigates a display response from the bound ComboBox providng a previous selection had a different “Status ID”. What have I dont wrong that would cause this behaviour?
So the form load looks like this
private void ProjectsForm_Load(object sender, EventArgs e)
{
InitBindingSource();
//// bind Selector
//ASMod$ this needs to be 'true' unless you explicitly declare columns
ProjectsDataGridView.AutoGenerateColumns = false;
ProjectsDataGridView.DataSource = ProjectsBindingSource;
GetData();
//Set GeneralStatusBox
Helpers.GeneralStatusInitLookup(statusComboBox, ProjectsBindingSource);
}
The ProjectBindingSource is initialised thus:
private void InitBindingSource()
{
ProjectsBindingSource = new BindingSource();
projectsBindingNavigator.BindingSource = ProjectsBindingSource;
ProjectsBindingSource.PositionChanged += new EventHandler(ProjectsBindingSource_PositionChanged);
}
A ProjectsAddDataBindings procedure, and the contained DataBindings.Add for the ComboBox (executed at the end of a GetData routine that additionally populated ProjectsBindingSource):
ProjectsAddDataBindings();
{
…
this.statusComboBox.DataBindings.Add("Text", ProjectsBindingSource, "GSID");
…
}
After the GetData block the GeneralStatusInitLookup populates the Lookup elements, in a helper class simply because it provides functionality to a number of different forms
public static void GeneralStatusInitLookup(System.Windows.Forms.ComboBox comboBox, BindingSource primaryBindingSource)
{
string statusFilter = "";
statusFilter = Helpers.GetStatusGroupFilter(EndeavourForm.FilterId);
if (statusFilter != "")
{
statusFilter = " WHERE " + statusFilter;
}
//// string statusFilter = ""; //// temp
string sql = "";
sql = "SELECT GSID, ShortName FROM GeneralStatus" + statusFilter + " ORDER BY Pos";
GeneralStatusDataTable = Helpers.Db.GetDataTable(sql);
comboBox.DataSource = GeneralStatusDataTable;
comboBox.DisplayMember = "ShortName";
comboBox.ValueMember = "GSID";
comboBox.DataBindings.Add(new Binding("SelectedValue", primaryBindingSource.DataSource, "GSID"));
}
And the DGV initiated row change is handled like this
private void ProjectsBindingSource_PositionChanged(object sender, EventArgs e)
{
try
{
// Update the database with the user's changes.
UpdateProjects();
statusComboBox.SelectedValue = (int)CurrentDataRowView.Row["GSID"];
}
catch (Exception)
{
}
}
private void UpdateProjects()
{
try
{
ProjectsDataAdapter.Update((DataTable)ProjectsBindingSource.DataSource);
DataHelper.CommitProposedChanges(projectsDataSet);
if (this.projectsDataSet.HasChanges() == true)
{
ProjectsBindingSource.EndEdit();
ProjectsDataAdapter.Update();
}
CurrentDataRowView = (DataRowView)ProjectsBindingSource.Current;
}
catch (InvalidOperationException)
{
throw;
}
catch (Exception)
{
throw;
}
}
Anyway I hope I haven't swamped readers with to much code, but frankly I cant see where this is going wrong. So any help would be greatly appreciated.
This was a simple solution in the end. Both the GeneralStatusInitLookup() and the ProjectsAddDataBindings() blocks made use of DataBindings.Add ... For the lookup table this was fine, but with the binding to the main table; the later, I had used "Text" as the propertyName parameter.
I've a custom combobox template because of some binding stuff that won't work with the 'default' ComboBoxColumn.
To make it look 'nice' I've one template for the edit mode (a Combobox) and one for the 'normal' mode (a Label).
Now, because of that I've to commit the edit made to the combobox manually inside the CellEditEnding event
private bool changeCommitInProgress = false;
private void table_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is ContentPresenter && e.EditAction == DataGridEditAction.Commit)
{
if (!changeCommitInProgress)
{
changeCommitInProgress = true;
DataGrid grid = (DataGrid)sender;
grid.CommitEdit(DataGridEditingUnit.Row, false);
changeCommitInProgress = false;
}
}
}
The problem with this is, that it'll remove the focus from the entire datagrid. Just to be on the safe side, these are the only properties I changed on the datagrid (aside from the Name property and the ItemsSource):
grid.AutoGenerateColumns = false;
grid.IsSynchronizedWithCurrentItem = true;
grid.SelectionUnit = DataGridSelectionUnit.Cell;
This is a fun question. I have done similar with a nested DataList where I had to add a new row after last entry and focus on the first textbox of the newly generated row, maybe you can extrapolate my strategy to fit your situation?
protected void calcAvg(object sender, CommandEventArgs e)
{
int row = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
DataListItem ActiveRow = dlMeasurements.Items[row];
// Snipped code doing stuff with current row
// Compare how many rows completed to number of rows requested
if (!(row + 1 == Convert.ToInt32(txtSample.Text)))
{
// Create new row
DataRow drNew = nextMeas.Tables[0].NewRow();
nextMeas.Tables[0].Rows.Add(drNew);
// Change item index and rebind
dlMeasurements.EditItemIndex = row + 1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
//Set focus with the Script Manager
smInspection.SetFocus((TextBox)(dlMeasurements.Items[row + 1].FindControl("txtRead1")));
}
else
{
// Otherwise close the measurements and show exit button
dlMeasurements.EditItemIndex = -1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
btnSaveAndPrint.Visible = true;
}
}
}
I have a DataTable which is populated from a CSV file then, using a DataGridView the data is edited in memory. As far as I understand the programmatic editing of the data should be done on the DataTable where the user editing is done via. the DataGridView.
However when I add columns programmatically to the DataTable, it is not reflected automatically in the DataGridView and I suspect the converse is also true.
How do you keep the two concurrent? I thought the idea of data binding was that this was automatic...
Also adding rows works fine.
SOLVED:
The AutoGeneratedColumns was set to false in the designer code despite being true in the properties dialog (and set explicitly in the code). The initial columns were generated programmatically and so should not have appeared however this was not picked up on since the designer code also continued to generate 'designed in' columns that were originally used for debugging.
Moral: Check the autogenerated code!
In addition to this, see this post and this post
This doesn't sound right. To test it out, I wrote a simple app, that creates a DataTable and adds some data to it.
On the button1.Click it binds the table to the DataGridView.
Then, I added a second button, which when clicked, adds another column to the underlying DataTable.
When I tested it, and I clicked the second button, the grid immedialtey reflected the update.
To test the reverse, I added a third button which pops up a dialog with a DataGridView that gets bound to the same DataTable. At runtime, I then added some values to the first DataGridView, and when I clicked the button to bring up the dialog, the changes were reflected.
My point is, they are supposed to stay concurrent. Mark may be right when he suggested you check if AutoGenerateColumns is set to true. You don't need to call DataBind though, that's only for a DataGridView on the web. Maybe you can post of what you're doing, because this SHOULD work.
How I tested it:
DataTable table = new DataTable();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
table.Columns.Add("Name");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("Alex", 26);
table.Rows.Add("Jim", 36);
table.Rows.Add("Bob", 34);
table.Rows.Add("Mike", 47);
table.Rows.Add("Joe", 61);
this.dataGridView1.DataSource = table;
}
private void button2_Click(object sender, EventArgs e)
{
table.Columns.Add("Height", typeof(int));
foreach (DataRow row in table.Rows)
{
row["Height"] = 100;
}
}
private void button3_Click(object sender, EventArgs e)
{
GridViewer g = new GridViewer { DataSource = table };
g.ShowDialog();
}
public partial class GridViewer : Form //just has a DataGridView on it
{
public GridViewer()
{
InitializeComponent();
}
public object DataSource
{
get { return this.dataGridView1.DataSource; }
set { this.dataGridView1.DataSource = value; }
}
}
Is AutoGenerateColumns set to true? If you are making changes after the initial Binding you'll also have to call DataBind() to rebind the changed datasource. I know this is true for an AJAX callback, I think it is true for a WinForms control PostBack.
Here is another solution which you dont need to assign a "name" to the data grid, so that the data grid can be a template element.
(In my case, data grid is a template element inside TabControl.ContentTemplate)
The key to show the new column (added programmatically after the initial binding) is forcing the datagrid to refresh.
From the answer in Force WPF DataGrid to regenerate itself, Andres suggested setting AutoGenerateColumns from false to true will force datagrid to refresh.
Which means I simply need to:
Bind the AutoGenerateColumns to a property of my object
Set the propery to false before adding column
Set the propery to true after added column.
Here is the code:
XAML:
<DataGrid AutoGenerateColumns="{Binding toggleToRefresh}"
ItemsSource="{Binding dataTable}"
/>
C#:
public class MyTabItem : ObservableObject
{
private DataTable _dataTable = new DataTable();
public DataTable dataTable
{
get { return _dataTable; }
}
private bool _toggleToRefresh = true;
public bool toggleToRefresh
{
get { return _toggleToRefresh; }
set
{
if (_toggleToRefresh != value)
{
_toggleToRefresh = value;
RaisePropertyChanged("toggleToRefresh");
}
}
}
public void addDTColumn()
{
toggleToRefresh = false;
string newColumnName = "x" + dataTable.Columns.Count.ToString();
dataTable.Columns.Add(newColumnName, typeof(double));
foreach (DataRow row in dataTable.Rows)
{
row[newColumnName] = 0.0;
}
toggleToRefresh = true;
}
public void addDTRow()
{
var row = dataTable.NewRow();
foreach (DataColumn col in dataTable.Columns)
{
row[col.ColumnName] = 0.0;
}
dataTable.Rows.Add(row);
}
}
Hope this help :)
I had the same issue and I issued a DataBind(). It's not the silver bullet for everything, but it's what helped me in a few cases. I had to put it in before capturing information through a DataView, after the EditCommand and UpdateCommand events immediately after the EditItemIndex statement,
protected void datalistUWSolutions_EditCommand(object source, DataListCommandEventArgs e)
{
datalistUWSolutions.EditItemIndex = e.Item.ItemIndex;
datalistUWSolutions.DataBind(); // refresh the grid.
}
and
protected void datalistUWSolutions_UpdateCommand(object source, DataListCommandEventArgs e)
{
objDSSolutions.UpdateParameters["Name"].DefaultValue = ((Label)e.Item.FindControl("lblSolutionName")).Text;
objDSSolutions.UpdateParameters["PriorityOrder"].DefaultValue = ((Label)e.Item.FindControl("lblOrder")).Text;
objDSSolutions.UpdateParameters["Value"].DefaultValue = ((TextBox)e.Item.FindControl("txtSolutionValue")).Text;
objDSSolutions.Update();
datalistUWSolutions.EditItemIndex = -1; // Release the edited record
datalistUWSolutions.DataBind(); // Redind the records for refesh the control
}