In MonoTouch, how can i immediately redraw an empty UITableView when i cleared its datasource?
List<string> ds = new List<string>();
UITableView tbl = new UITableView();
tbl.DataSource = new MyTableViewDataSource(ds);
//And the other parts(datasource class, delegate class etc.) are truely coded when i try to do somewhere at my program, something like
ds.Add("new string");
//it works and table shows new data too, but when i say
ds.Clear();
//it works and clear but table is not redrawn
Thanks
Are you calling tbl.ReloadData (); from somewhere ?
Related
I'm trying to read the contents from a SQL query and store them into a listView (Android-C#). For whatever reason the listView is only showing the last item. When I debug through the code, I see that it is going through every result, however, I cannot get the adapter to display all the results. Maybe I am doing something wrong with the adapter. Any ideas?
Code:
while (rdr.Read ()) {
string[] Text = new string[] { (rdr[0])+ System.Environment.NewLine} ;
ListView mylistview = FindViewById<ListView> (Resource.Id.listView1);
var myAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1 , Text);
mylistview.Adapter = myAdapter;
}
For whatever reason the listView is only showing the last item.
Because in while every time new Text Array is created and pass to ArrayAdapter so last is Array data is showing in ListView.
To show all items in ListView,create Adapter object outside while loop and use ArrayList which will grow according to data-size:
ArrayList listText = new ArrayList();
while (rdr.Read ()) {
listText.add((rdr[0])+ System.Environment.NewLine);
}
ListView mylistview = FindViewById<ListView> (Resource.Id.listView1);
var myAdapter = new ArrayAdapter(this,
Android.Resource.Layout.SimpleListItem1,listText);
mylistview.Adapter = myAdapter;
There are a lot of questions similar to mine but my problem is in the inverse of the typical question: I am unable to get the items in a master Combobox shows up correctly when moving along the detail recordset. I am quite new to Ado.Net so, please, expect some mess: my knowledge about the ADO.NET data object model is still poor; anyways this is my code:
private DataSet MainDataSet = new DataSet("MainDataSet");
BindingSource DetailBindingDataSource = new BindingSource();
BindingSource MasterBindingDataSource = new BindingSource();
SqlCeDataAdapter MasterDataAdapter;
SqlCeDataAdapter DetailDataAdapter;
MainDataSet.EnforceConstraints = true;
MasterDataAdapter = new SqlCeDataAdapter(GET_MASTERS_SQL_COMMAND, CONNECTION_STRING);
DetailDataAdapter = new SqlCeDataAdapter(GET_DETAILS_SQL_COMMAND, CONNECTION_STRING);
GetData(MainDataSet, ImagesDataAdapter, "masters"); // just a wrapper
GetData(MainDataSet, DefectsDataAdapter, "details"); // just a wrapper
DataTable DetailTable = MainDataSet.Tables["details"];
DataTable MasterTable = MainDataSet.Tables["masters"];
DetailBindingDataSource.DataSource = DetailTable;
MasterBindingDataSource.DataSource = MasterTable;
// establishing relationships between Master / Detail data
// to keep in sync related comboboxes with BindingNavigator
DataRelation DetailHasMaster = new DataRelation("DetailHasMaster", MainDataSet.Tables["masters"].Columns["master"], MainDataSet.Tables["details"].Columns["details"]);
MainDataSet.Relations.Add(DetailHasMaster);
BindingNavigator SearchNavigator = new BindingNavigator(true);
SearchNavigator.BindingSource = DetailBindingDataSource;
// Just as example, binding some fields: this is working, data change when moving on with BindingNavigator
DataTextBox.DataBindings.Add(new Binding("Text", DetailBindingDataSource, "creationDate"));
ItemTextBox.DataBindings.Add(new Binding("Text", DetailBindingDataSource, "partnumber"));
SerialNumTextBox.DataBindings.Add(new Binding("Text", DetailBindingDataSource, "SerialNumber"));
NoteTextBox.DataBindings.Add(new Binding("Text", DetailBindingDataSource, "note"));
/*
* Assign data origin to the binding sources;
* this is NOT working, the master combobox do not changes when moving
* on with BindingNavigator
*/
MasterComboBox.DataSource = MasterBindingDataSource;
MasterComboBox.DisplayMember = "name";
MasterComboBox.ValueMember = "master";
private void GetData(DataSet CurrentDataSet,
SqlCeDataAdapter CurrentDataAdapter,
String TableName)
{
CurrentDataAdapter.FillSchema(CurrentDataSet, SchemaType.Source, TableName);
CurrentDataAdapter.Fill(CurrentDataSet, TableName);
SqlCeCommandBuilder GenericCommandBuilder = new SqlCeCommandBuilder(CurrentDataAdapter);
CurrentDataAdapter.UpdateCommand = GenericCommandBuilder.GetUpdateCommand();
CurrentDataAdapter.InsertCommand = GenericCommandBuilder.GetInsertCommand();
}
Have someone pointers to the right solution?
Thanks
Not sure if this is a proper solution: my idea was that the combobox could be updated automatically by means of some property or method of the involved objects. The quick and dirty solution I have implemented is:
Subscribe the BindingSource.CurrentChanged event to be notified about stepping along the data
Check for: if (BindingSource.Count == 0)
Update manually the ComboBox.SelectedValue with values from the current row.
I believe that a better and more ADO capabilities - aware must exists, but this anyway saved my Sunday.
I have a couple of ComboBoxes on a Win Form that I always set list to the DataSource like this:
aComboBox.DataSource = someList;
foreach(Object obj in aComboBox.Items) {
// do something
}
This works perfectly fine for me, however, I have some trouble when trying to reset the data like this:
aComboBox.DataSource = null;
aComboBox.DataSource = someOtherList;
foreach(Object obj in aComboBox.Items) {
// do something else
}
The DataSource is reset successfully, but that does not trigger to reset the Items. I tried to call aComboBox.Items.Clear() to clean up the Items, no resetting happened.
Have I missed something?
Looks like that is all because of the form is "owned" by another form, where I have it child.Show(this) in the parent form to have the convenient to access methods from the parent form in the child.
In addition, using the BindingSource to look after the data binding will do the trick. This is what I've done:
BindingSource bs = new BindingSource;
aComboBox.DataSource = bs;
bs.DataSource = someList;
//
// after some processing
//
bs.DataSource = null;
bs.DataSource = someOtherList;
Try steps in this sequence
cmbBox.Items.Clear();
cmbBox.DataSource = SomeOtherList;
cmbBox.DataBind();
This is a multi threaded scenario.
The main thread handles the application and UI events, and it starts up a new thread to do some background operations.
The "background" thread loads the data from files into a data-table of a strongly-typed dataset. The DataGridView is bound to that DataTable.
Once the data is ready, the "background" thread invokes the refresh() function of the DataGridView on the form.
If there are more lines then what fits on one screen and the vertical scrollbar is to appear: the grid crashes. The new datalines are always displayed. Error only occurs if there are enough lines to display the scrollbar (see image below).
I use .NET 3.5. In Windows XP it crashes the whole application. On Win 7 (64 bit) only the grid becomes unresponsive, but once I resize the window the scrollbar appears and all is fine.
The relevant parts of the code are attached below.
Grid refresh operation in the form's .cs file:
public void ThreadSafeRebindGrids()
{
SimpleCallBack callBackHandler = new SimpleCallBack(RebindGrids);
this.BeginInvoke(callBackHandler);
}
public void RebindGrids()
{
gridCurrentResults.Refresh(); // The problematic DataGridView refresh()
gridAllResults.Refresh();
}
public delegate void SimpleCallBack();
The update part in the "background" thread:
void Maestro32_SampleFinished(object sender, MeasurementEvents.SampleFinishedEventArgs e)
{
//--- Read new results
ParentForm.ThreadSafeSetStatusInfo("Processing results for sample no. " + e.SampleNo.ToString() + "...");
CurrentMeasurement.ReadSpeResults(); // Updating the DataTable in the strongly typed DataSet (see below)
ParentForm.ThreadSafeRebindGrids(); // Refresh the DataGridView
ParentForm.ThreadSafeRefreshNumbers();
}
The objects related to the "background" thread have a direct reference to the DataSet (UiDataSource). The DataTable (CurrentSamples) is updated in the following manner:
/// <summary>
/// Adds a new sample to the CurrentSamples table of the UiDataSet.
/// </summary>
/// <param name="sample">The new sample to be added to the table.</param>
/// <param name="serial">The serial number of the sample being added</param>
private void AddSampleToCurrentResults(SampleData sample, int serial)
{
UiDataSource.CurrentSamples.AddCurrentSamplesRow(serial,
sample.MeasurementDate,
(uint)Math.Round(sample.SampleCountSum),
true, //--- Set the checkbox checked
sample.LiveTime,
sample.RealTime);
}
DataGridView options:
//
// gridCurrentResults (generated)
//
this.gridCurrentResults.AllowUserToAddRows = false;
this.gridCurrentResults.AllowUserToDeleteRows = false;
this.gridCurrentResults.AllowUserToOrderColumns = true;
this.gridCurrentResults.AllowUserToResizeRows = false;
this.gridCurrentResults.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gridCurrentResults.AutoGenerateColumns = false;
this.gridCurrentResults.CausesValidation = false;
this.gridCurrentResults.ColumnHeadersHeight = 25;
this.gridCurrentResults.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.selectedCol,
this.SampleNoCol,
this.MeasuredValueCol,
this.liveTimeCol,
this.realTimeDataGridViewTextBoxColumn,
this.AtTimeCol});
this.gridCurrentResults.DataMember = "CurrentSamples";
this.gridCurrentResults.DataSource = this.uiDataSource;
this.gridCurrentResults.Location = new System.Drawing.Point(11, 24);
this.gridCurrentResults.Margin = new System.Windows.Forms.Padding(8);
this.gridCurrentResults.Name = "gridCurrentResults";
this.gridCurrentResults.RowHeadersVisible = false;
this.gridCurrentResults.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.gridCurrentResults.ShowEditingIcon = false;
this.gridCurrentResults.Size = new System.Drawing.Size(534, 264);
this.gridCurrentResults.TabIndex = 0;
this.gridCurrentResults.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.gridCurrentResults_CellContentClick);
If I made a mistake somewhere please point it out to me.
#ChrisF:
I tried removing the refresh() statement, as I am doing pretty much the same what u suggested. The only difference is the databinding, it looks like:
this.dataGridView.DataSource = this.dataSet;
this.dataGridView.DataMember = "dataTable";
And I update the dataTable in a similar way, but from another thread.
But the new data lines do not appear until I, say, resize the window.
Which raises the question how I can properly update the dataTable from another thread?
I'm guessing the problem has to do with how WinForms works inside the STA model for threading. Basically, the DataTable you're accessing is located somewhere, and that is probably inside the form we see above. So, when you update the DataTable from another thread, which thread gets the events needed for binding? Likely the thread you update it from, and the form's thread is not aware of the changes being made. So, you simply need to invoke any calls to DataTable onto the form itself, so it receives the events properly:
this.Invoke(() => {
// any calls involving DataTable
});
It seems backwards, but keep in mind in an "enterprise" situation, you'd probably be accessing that dataset by multiple adapters. So, your update thread would have an adapter to itself, and your GUI would have its own also. The other solution would be to use a BindingList, which I believe has thread compatibility for this type of situation, but don't quote me on that.
For extra credit, this could also explain your problem before with crashing. By accessing the DataGridView from the background thread, you had cross-thread operations going on.
I wouldn't call:
gridCurrentResults.Refresh(); // The problematic DataGridView refresh()
gridAllResults.Refresh();
These will take progressively longer and longer as the data set gets larger and larger.
I've written an application that uses a DataGridView to display mp3 file information. I set the DataSource of the DataGridView to a DataTable:
this.dataGridView.DataSource = this.dataTable;
and then simply add the new information to the DataTable:
this.dataTable.Rows.Add(row);
This automatically updates the DataGridView.
Goal:
Once clicking on add or delete button, the datagridview should be refreshed with the latest data from document.
Problem:
The datagridview can't be refreshed
after making changes by deleting or
adding new data.
I'm using binding source that is linked with datagridview's datasource.
I tried everything with different solution and read advise from different forum but still I can't solve this problem.
I also tried using these syntax "BindingSource.ResetBindings(false)", "BindingSource.Refresh()" etc but no result.
Links below:
How to refresh a bindingsource
http://www.eggheadcafe.com/community/aspnet/2/10114324/datagridview-refresh-from-another-form.aspx
http://blogs.msdn.com/b/dchandnani/archive/2005/03/15/396387.aspx
http://bytes.com/topic/c-sharp/answers/812061-problem-refresh-datagridview
bSrcStock.DataSource = myProductrepository.GetAllProductList();
dgridStock.DataSource = null;
dgridStock.DataSource = bSrcStock;
bSrcStock.ResetBindings(true);
dgridStock.Columns[0].Width = 101;
dgridStock.Columns[1].Width = 65;
dgridStock.Columns[2].Width = 80;
dgridStock.Columns[3].Width = 120;
dgridStock.Columns[4].Width = 90;
I have faced this same issue and found out that the problem is with the initialization of the BindingSource inside a static constructor (The class was a singleton). Upon realizing this, I moved the code to the calling event and it finally worked without needing to assign null or call the clear method. Hope this helps.
No need to define the columns (unless you really want to...)
Then just call for the refreshDataGridView Method every time you add or remove something from your list...
public List<CustomItem> ciList = new List<CustomItem>();
CustomItem tempItem = new CustomItem();
tempItem.Name = "Test Name";
ciList.add(tempItem);
refreshDataGridView();
private void refreshDataGridView()
{
dataGridView1.DataSource = typeof(List<>);
dataGridView1.DataSource = ciList;
dataGridView1.AutoResizeColumns();
dataGridView1.Refresh();
}
You need a list that will inform the BindingSource when an item is added etc. Use a System.ComponentModel.BindingList for that.
Dim lisItems As New System.ComponentModel.BindingList(Of myObject)
Works Great! Only AddRange is missing so this takes care of that:
Private Sub AddRange(ByVal lis As List(Of myObject))
For Each itm In lis
lisItems.Add(itm)
Next
End Sub
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.bindinglist-1?view=netframework-4.7.2