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
Related
I have tow form,ListFrom, and DetailForm
In the ListForm I have a devexpress grid and some button(add, delete, edit)
In the DetailForm I have some textboxes and some button(save,delete,next,previous)
well I have to senario
1 - I open the ListForm and I click on a product to modify it a got the DetailForm opened, I make some modification and I save,then i should have my grid in the ListForm refreshed with the new value.for this I have this code
In the ListFrom
FrmProduit frm = new FrmProduit(monProduit.Id) { MdiParent = this.MdiParent};
frm.updateDataInGridView += new System.Action(refereshGridView);
frm.Show();
in the detailform
if (updateDataInGridView != null)
updateDataInGridView();
well in this scenario everything is OK
second scenario
If I open the detailFrom,and after that I open the listForm, I make some change in the detailFrom and I click save updateDataInGridView in this case is null and then the grid is not refreshed
anyone have suggestion?
I would create a shared BindingSource that both forms would use to show data. If any item is changed in BindingSource it takes care to notify all controls bind to it and so it would refresh grid automatically.
Second approach is to make refereshGridView method public and in DetailForm on save click do this:
var lists = Application.OpenForms.OfType<Form>().Where(x => x.GetType() == typeof(ListFrom));
foreach (var listform in lists)
{
listform.refereshGridView();
}
I did not use FirstOrDefault as maybe there is more than one listform opened.
EDIT about Binding Source
Here is quite good tutorial so please take a look.
Below is a fast-written far from best example of stretch I did:
internal static class DataSources
{
private static BindingSource bs;
public static BindingSource CerateDataSource(List<object> yourObjects)
{
bs = new BindingSource();
bs.DataSource = yourObjects;
}
public static BindingSource GetDataSource()
{
return bs;
}
public static void Reset()
{
bs.ResetBindings(false);
}
}
and then in your listview
dataGridView1.DataSource = DataSources.GetData();
and in detailsview where you are editing one of the objects from BindingSource on save you would have to call: DataSources.Reset();. This is just a markup, but hopefully you get the idea :).
You must always be sure you are referring to the current instance of detailform, thus declare on your listForm
detailform obj = (detailform)Application.OpenForms["detailform"];
And every time you call detailform from listForm do it by obj e.g:
obj.Show()
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();
}
int[] arr = int[100];
listBox1.DataSource = arr;
void ComboBox1SelectedIndexChanged(object sender, EventArgs e)
{
.....//some processes
listBox1.DataSource = null;
listBox1.DataSource = arr;
}
is not working,
also,
listBox1.Refresh(); is not working,
also,
listBox1.Update(); is not working,
i know i can use BindingList<T> but i have to work with only array.
can you help me how can i refresh listbox?
my first answer on stack exchange here.
C# .Net 4.0:
listBox1.DataSource = null;
listBox1.DataSource = names;
I noticed that setting the datasource for the first time, it refreshes.
When it's set, and you try set it to the same one again, it doesn't update.
So I made it null, set it to the same one, and it displayed correctly for me with this issue.
ListBox only updates its shown content when the object that is binded on dataSource notifys it own changes. the BindingSource object has an event called DataSourceChanged. when the Source is changed to a different object the Listbox will update itself.
Same thing when you bind a List. Nothing will happen if you change the List, because the List doesn't notify that it has been changed. There is a Simple solution for this Problem: use BindingList
http://msdn.microsoft.com/de-de/library/ms132679%28v=vs.110%29.aspx
the BindingList has the ListChanged Event is called every time when the List is changed (obviously). So the DataBindings of Windows.Form objects use events like ListChanged to update themselves. A simple List doesn't support this event.
SO if you want to work with a lot of Data Bindings you should know about:
http://msdn.microsoft.com/de-de/library/system.componentmodel.inotifypropertychanged%28v=vs.110%29.aspx
Managed to do just with
FirstListBox.DataContext = null;
FirstListBox.DataContext = App.ViewModel;
Simply loses link and get all the data back to it.
I inherited ListBox and added a public method calling RefreshItems() which does what we want. Already implemented and all. I dont know why they didnt put in a public method.
The problem might come from the ListBox SelectionMode.
For a reason that I don't know, the databinding does not work when SelectionMode is SelectionMode.None.
A workaround could be:
listBox.SelectionMode = SelectionMode.MultiExtended;
listBox.DataSource = myDatasource;
listBox.SelectionMode = SelectionMode.None;
Hope it helps.
well, without binding I only managed with:
this.Hide();
this.Show();
it redraws everything...
try the following
listBox1.DataBind()
Use BeginUpdate and EndUpdate, that should solve it.
No need to set the data source twice
listBox1.BeginUpdate();
listBox1.DataSource = myList;
listBox1.EndUpdate();
Windows forms to see changes especially on Listbox and other controls before load is finished is tricky.
To see data as its loaded use invalidate(); then Update();
Quick Answer
BindingSource bs = new BindingSource();
bs.DataSource = arr;
listbox1.DataSource = bs;
arr[0] = 100; //Do some value change
bs.ResetBindings(false); //Refresh the listbox
Explanation
As stated by Microsoft:
The BindingSource component serves two purposes. First, it provides a layer of indirection when binding the controls on a form to data. This is accomplished by binding the BindingSource component to your data source, and then binding the controls on your form to the BindingSource component. All further interaction with the data, including navigating, sorting, filtering, and updating, is accomplished with calls to the BindingSource component.
So, if you have multiple Controls binded with same data which changes frequently, it is suggested to use BindingSource rather than setting DataSource property of the Controls directly to an Array or List etc.
Moreover, with decompiling ListBox class which is inherited from ListControl in .net 4.6.2, the setter of property DataSource is:
if ((value != null) && (!(value is IList) && !(value is IListSource)))
{
throw new ArgumentException(System.Windows.Forms.SR.GetString("BadDataSourceForComplexBinding"));
}
if (this.dataSource != value)
{
try
{
this.SetDataConnection(value, this.displayMember, false);
}
catch
{
this.DisplayMember = "";
}
if (value == null)
{
this.DisplayMember = "";
}
}
We can see if the value is null the DisplayMember property will automaticly be set to empty. And when you reset a value, several initialization will be performed in SetDataConnection method which takes extra cost.
In contrast, calling BingdingSource.ResetBindings only fires an event:
public void ResetBindings(bool metadataChanged)
{
if (metadataChanged)
{
this.OnListChanged(new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, null));
}
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
Although I didn't find the handler in ListBox but I guess there should be less side effects. So I think the highest voted answer is not the best solution.
I have a datagridview which we will call dataGridViewExample.
My object (the uncommon datatypes is because my database is SQLite):
class MyObject
{
public Int64 Vnr { get; set; }
public string Name { get; set; }
public Single Price { get; set; }
public int Amount { get; set; }
}
Here is the relevant code:
//This form gets called with a .ShowDialog(); in my form1.
private List<MyObjecte> ExampleList = new List<MyObject>();
public MyForm()
{
dataGridViewExample.DataSource = OrdreInkøbsListe;
}
private void AddtoDataGridViewExample()
{
//Add a new MyObject to the list
ExampleList.Add(new myObject()
{
Vnr = newVnr,
Amount = newAmount,
Price = newPrice,
Name = newName
});
//refresh datasource
dataGridViewExample.DataSource = null;
dataGridViewExample.Refresh();
dataGridViewExample.DataSource = OrdreInkøbsListe;
ddataGridViewExample.Refresh();
}
When MyForm gets called with a .ShowDialog, it shows up fine and displays my DataGridView example just fine. As you can read from the code, the ExampleListis initially empty, so it just shows an empty datagridview with 4 columns: Vnr, Name, Price & Amount. If I click inside it etc. nothing happens - so everything is working as planned, so far.
Everytime I call AddtoDataGridViewExample() it adds the new object to the Datagridview, and the datagridview does update, listing all the objects added so far (they show themself as rows, again according to plan).
Now, remember that I just said that nothing happened if you clicked inside DataGridViewExample before I have called AddtoDataGridViewExample()?
Well, after having called AddtoDataGridViewExample() once or more, the program will crash if I click inside DataGridViewExample (for example: the users wants to select a row). It throws an IndexOutOfRangeException and talks about an -1 index.
It also throws the exception in the other form, on the line where I call MyForm with .ShowDialog();
I really am stuck on this, do you guys have any idea what is wrong??
My only clue is that I do believe the refresh of DataGridViewExample's datasource might be the cause of the problem.
Another important note: I have yet bound any events to my DataGridViewExample. So you can rule that idea out.
Here is all DataGridViewExample's properties:
this.dataGridViewExample.AllowUserToAddRows = false;
this.dataGridViewExample.AllowUserToDeleteRows = false;
this.dataGridViewExample.AllowUserToResizeColumns = false;
this.dataGridViewExample.AllowUserToResizeRows = false;
this.dataGridViewExample.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dataGridViewExample.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridViewExample.Location = new System.Drawing.Point(591, 53);
this.dataGridViewExample.MultiSelect = false;
this.dataGridViewExample.Name = "dataGridViewExample";
this.dataGridViewExample.ReadOnly = true;
this.dataGridViewExample.RowHeadersVisible = false;
this.dataGridViewExample.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dataGridViewExample.ShowEditingIcon = false;
this.dataGridViewExample.Size = new System.Drawing.Size(240, 150);
this.dataGridViewExample.TabIndex = 31;
I guess the click event tries to get the currently selected row and do something with it, while dataGridViewExample.DataSource = null; clears the datasource, and the currently selected row becomes null.
If you set the DataGridView.DataSource to the list, you don't need to reset it to null, refresh, and reset it to the list again (and refresh again) to see the changes. It will be enough to just refresh the DataGridView.
You can also just try using an BindingList<T> object instead of a List<T>, which will automatically notify your grid of its internal changes (Adding and removing elements), and there's also an INotifyPropertyChanged interface you can implement on your MyObject class, that will make every property change in an object show on the grid (For any changes made to the object in the code, and not through the grid itself).
Have you tried running the debugger and break when InedxOutOfRangeException is thrown to see where the exception is thrown?
Select Debug > Exceptions then there's a Find button on the dialog so you don't have to browse through all of the possibilities.
I had similar situation. I assigned generic list of certain object to DataGridView. Then I was setting null to DataSource and after that refresh. After that I assign list of objects to DataSource. While clicked on grid while runtime error occured IndexOutOfRange. My solution was to assign new empty list of my object to that grid and refresh and after changes on my working list I do assign to DataSource and call Refresh. Now, it is working without any crashes. Please look on my code before:
grid.DataSource = null;
grid.Refresh();
if(cases.Count() > 0)
{
grid.DataSource = cases;
grid.Refresh();
}
And now on my code after:
grid.DataSource = new List<MyCase>();
grid.Refresh();
//do something with cases
if(cases.Count() > 0)
{
grid.DataSource = cases;
grid.Refresh();
}
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.