I've got the following code which I think ought to be binding a DataTable to a DataGridView, but the DataGridView shows up empty. The DataTable definately has rows, so I assume that I am binding the DataSource incorrectly some how. Does anyone see what is wrong with this:
DataBase db = new DataBase(re.OutputDir+"\\Matches.db");
MatchDBReader reader = new MatchDBReader(db.NewConnection());
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = reader.GetDataTable();
this.dataGridView1.DataSource = bindingSource.DataSource;
The first line simply gets a handle to the DB that I'm pulling data from.
The next line is a provides a class for reading from that same db - in particular it exposes the GetDataTable method with returns the data table that I intend to put into the DataGridView.
The next line is uninteresting...
The 4th line attempts to grab the DataTable - QuickWatch indicates that this is working...
The final line is where I assume i've screwed up...my understanding is that this binds the DataTable to the DataGridView GUI, but nothing shows up.
Any thoughts?
Try binding the DataGridView directly to the BindingSource, and not the BindingSource's DataSource:
this.dataGridView1.DataSource = bindingSource;
You need to attach your BindingSource to your grid, before you get the data table.
Try switching the last two lines of code:
DataBase db = new DataBase(re.OutputDir+"\\Matches.db");
MatchDBReader reader = new MatchDBReader(db.NewConnection());
BindingSource bindingSource = new BindingSource();
this.dataGridView1.DataSource = bindingSource.DataSource;
bindingSource.DataSource = reader.GetDataTable();
Along with above solutions also fix the "bindingSource" datamember property. like:
bindingSource.DataMember = yourDataSet.DataTable;
I had the same problem with sql database and datagrid view. After a great deal of trouble I found out that I've forgot to set dataMember property of my binding source.
best of luck.
None of this worked for me, though it all seemed like good advice. What I ended up doing was the biggest, worst hack on earth. What I was hoping to accomplish was simply to load a DB table from a SQLite db and present it (read only, with sortable columns) in the DataGridView. The actual DB would be programmatically specified at runtime. I defined the DataSet by adding a DataGridView to the form and used the Wizards to statically define the DB connection string. Then I went into the Settings.Designer.cs file and added a set accessor to the DB Connection string property:
namespace FormatDetector.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)]
[global::System.Configuration.DefaultSettingValueAttribute("data source=E:\\workspace\\Test\\Matches.db;useutf16encoding=True")]
public string MatchesConnectionString {
get {
return ((string)(this["MatchesConnectionString"]));
}
set
{
(this["MatchesConnectionString"]) = value;
}
}
}
}
This is a klugey hack, but it works. Suggestions about how to clean this mess up are more than welcome.
brian
DataGridView takes a DataTable as a basis. The DataTable Columns save their Type as a property.
If this type is an Interface all you would see are empty cells.
Related
I write a small program to record data change,it use a DataGridView,and it's datasource is a List, but I have a question on the DataBingding.
DataTable dataTable = GetBalance();
List<StockBalance> balances = ReadDataTable(dataTable);
List<StockBalance> stockBalances = (List<StockBalance>)dataGridView1.DataSource ?? new List<StockBalance>();
stockBalances.AddRange(balances);
dataGridView1.DataSource = stockBalances;
The above code can't refresh DataGridView, the data in balances will not show in DataGridView while stockBalances contains all new data, but the under code can archieveļ¼
balances.AddRange(stockBalances);
dataGridView1.DataSource = balances;
I guess the reason is List and StockBalance is reference type,but I don't konw how to validate it, or it's not that?
Hope someone can help me, thanks.
A DataGridView - any bound control in fact - needs to receive a notification from the data source when the data changes in order to know that it needs to update. That requires an object that implements the IBindingList interface. The List<T> does not implement that interface and so the grid has no idea when data changes in the list and thus doesn't update.
What you should do is bind your list to a BindingSource and then bind that to the grid. In that case, when you make changes to the list you can then call an appropriate method of the BindingSource, e.g. ResetBindings, to provide an appropriate notification to the grid.
Note that, when I say "notification", I'm talking about an event. An IBindingList object raises its ListChanged event and the control handles that event.
You can do it using a Binding source:
var source = new BindingSource();
List<StockBalance> balances = ReadDataTable(dataTable);
List<StockBalance> stockBalances = (List<StockBalance>)dataGridView1.DataSource ?? new List<StockBalance>();
stockBalances.AddRange(balances);
source.DataSource = stockBalances;
dataGridView1.AutoGenerateColumns=true;
dataGridView1.DataSource = source;
I am trying to bind data from several datagrids and I don't want to view all of them every time I start app.
Is there any possibility to set it in settings? Or automaticaly set all datagrids as viewed?
Thanks
Maybe your thinking about this the wrong way? If you want your data before the table is shown what you need to do is get and store the data in a DataTable and then use that to play with. Then when it comes to displaying your DataGridView just simply bind the DataTable to it and display it. I have included a sample below. But if its just a case of showing the tables then either tablename.visable = false should do the trick or alternitivly if you have other elements such as a panel you could use panelname.BringToFront or tablename.SendToBack.
Lets begin the OOP example..
This you could have in another interface class where you want to manipulate the data. In this example this class would be IOptions, here you could have all the data tables you need for Options for example. You could have different Interface Classes representing certain parts of your program, but we will stick with options for now..
public DataTable mProgramOptionsList;
Then when the program starts (your main page / main.cs) you attach IOptions to any of the classes that need at this DataTable.
mIOptions = new IOptions();
mPresenterOptions = new PresenterOptions();
mPresenterOptions.AttachInterface(mIOptions);
mModelOptions = new ModelOptions();
mModelOptions.AttachInterface(mIOptions);
Example code in PresenterOptions()
IOptions mIOptions;
public void AttachInterface(IOptions pOptions)
{
mIOptions = pOptions;
}
Now in Presenter Options you can modify the tables as you please, as well as fill them..
mIOptions.mProgramOptionsList = mModelOptions.GetProgOptionsFromDB();
This is the class you want to have your table control in. This could be a separate GUI/View class with its own layout and structure. As long as you have attached the Interface (IOptions) to the class your using to hold all your tables.
private IOptions mIOptions;
private BindingSource mbsProgramOptions;
public int mOptionsID { get; set; }
void AttachOptionsInterface(IOptions pOptions)
{
mIOptions = pOptions;
CreateDataBindings();
}
private void CreateDataBindings()
{
mbsProgramOptions= new BindingSource();
mbsProgramOptions.DataSource = mIOptions.mProgramOptionsList; // Or what ever datatable you have made
dgvProgramOptions.AutoGenerateColumns = false;
dgvProgramOptions.DataSource = mbsProgramOptions; // this binds your DataGridView to the DataSource
}
Once this is done not only can you add or change the data to any class you have attached IOptions too you can also display the table anywhere you please by just doing something like (Assuming you called your table control class above TableHelper):
In the PresenterOptions or any class for that matter:
TableHelper ProgramOptionsList;
ProgramOptionsList.mOptionsID = 1234; // Accessing a public/get;set; variable in TableHelper Class
ProgramOptionsList.Text = "Table Title";
ProgramOptionsList.ShowDialog();
ProgramOptionsList.BringToFront(); // Just in case you have multiple tables over lapping each other in TableHelper
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.
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
I am new with the subsonic, and I have a problem when trying to update the database from the sql server. I have created a gridview by still is not returning the updates results. can you please help me? its getting an error code on dc.AddMostaHse();
(Cannot implicity convert type 'void to 'object')
Here is the code being done of DataAccess.cs page
public void AddMostaHse()
{
Mosta.MostaHSE1 xx = new MostaHSE1();
xx.ID = 94;
xx.FunctionLocation = "lza94";
xx.acno = 12;
xx.Save();
}
Binding it with the gridview.
{
DataAccess dc = new DataAccess();
gvtest.DataSource = dc.AddMostaHse();
gvtest.DataBind();
}
This doesn't make much sense. Your gridview should be being bound from a Read operation. You are currently binding it to a Insert/Write operation based on what you have provided. You should probably be grabbing a collection of MostaHSE1() and displaying that in your gridview. The return type of your Read function should most likely be DataTable or DataSet.
Your AddMostHse1() appears it should work, but you want to target a different event off of the gridview to do this. Maybe RowEditEnding or some other event.
Your method AddMostaHse is returning void (no return). You cannot bind a datagrid to void. If you want to bind the datagrid to the object you just created in the method then change your method to:
public MostaHSE1 AddMostaHse() {
Mosta.MostaHSE1 xx = new MostaHSE1();
xx.ID = 94;
xx.FunctionLocation = "lza94";
xx.acno = 12;
xx.Save();
return xx;
}
It seems strange to me why you are binding one object to a datagrid (letting alone why would you bind a created object like that to a datagrid, I assume you are just testing), usually you bind a collection of objects..therefore this may not bring the result you want.
A more common candidate for your datagrid would be something like:
public IEnumerable<MostaHSE1> GetAllMostaHse() {
return Mosta.MostaHSE1.All();
}