ComboBox Items not refresed after reseting DataSource - c#

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();

Related

Want to add certain items from a list to a DataSource

A brief intro
The program runs a test on the machines. Then a dialogBox appears asking the user if all the machines worked correctly. If they say no another window appears with the dataGridView asking which machines failed through the checkBox method. This then sets the status to the ERROR status so the program can continue running while ignoring the machines with errors.
I have this class with the two properties
public class ASM
{
public byte DeviceID
public ASMStatus Status
}
I put this in a list
list<ASM001.ASM> ASMs = new list();
Now I want to add this list to a bindingSource in my dataGridView but only those whose Status equals ASMStatus.IDLE
I thought about just creating those that have idle into another list and attaching that to the binding list, however, the dataGridView also has a checkBox column that determines if the status needs to be changed to ASMStatus.ERROR
public partial class FailedMessageBox : Form
{
public FailedMessageBox()
{
InitializeComponent();
DataGridViewCheckBoxColumn col1 = new DataGridViewCheckBoxColumn();
col1.HeaderText = "Device Failed";
dataGridView1.Columns.Add(col1);
}
private void FailedMessageBox_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = Global.ASMs;
}
}
I want to make sure that when the user clicks OK the current ASMs in the list get set to ERROR which is why I thought a bindinglist would work the best
I am wondering if there was a quick way to do this or if I just have to do a bunch of loops.
What about something similar in your Page_load:
using(var context = new DbContext())
{
// You could put a Where Clause here to limit the returns
// i.e. context.ASMs.Where(s => s.Status == ASMStatus.IDLE).Load()
context.ASMs.Load();
var data = context.ASMs.Local.ToBindingList();
var bs = new BindingSource();
bs.DataSource = data;
dataGridView1.DataSource = bs;
}
You should add a BindingSource directly to the page but I am just showing adding it in code. Then you can access it like this:
foreach(DataRow row in dataGridView1.Rows)
{
if ((bool) row.Cells["Device Failed"].Value == true)
{
var line = row.DataBoundItem();
line.Status = ASMStatus.ERROR;
}
}
Make sure you save the changes.

Updating data from other form

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()

data grid view not working

I have developed a form in c# which is called inside a console application.
Below is how i have called the form inside the console.
Application.Run(new Form1(display_list));
displaylist is a list of struct
List , form_columns is a struct consisting of 3 string values which needs to be displayed side by side in a datagrid.
Below is the constructor of the form
public Form1(List<form_columns> disp)
{
InitializeComponent();
BindingSource source = new BindingSource();
source.DataSource = disp;
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = source;
}
But when the program is run , the datagridview is empty. it is not showing any data .
What mistake am i making?????
Try to bind the list using BindingList
BindingList<form_columns> bl = new BindingList<form_columns>(disp);
BindingSource source = new BindingSource(bl, null);
//source.DataSource = disp;

Can't refresh datagridview with bindingsource

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

ComboBox items.count doesn't match DataSource

I have a ComboBox that is bound to a DataSource. I want to dynamically add items to the ComboBox based on certain conditions. So what I've done is add the options to a new list, and then change the DataSource of the ComboBox like so:
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Then, I check cbo.Items.Count, and it has not incremented - it does not equal the count of the DataSource. Any ideas what I can do here?
Note this is WinForms and not ASP.NET.
Did you check the Count immediately or at a later time? There is the possibility that the ComboBox does not actually update it's contents until there is an operation such as a UI refresh and hence the count will be off until that time.
On case where this may happen is if you update the DataSource before the Handle is created for the ComboBox. I dug through the code a bit on reflector and it appears the items will not be updated in this case until the ComboBox is actually created and rendered.
If anyone experiences this problem on a dynamically added combobox, the answer is to ensure that you add the combobox to the controls of a container in the form.
By adding "this.Controls.Add(cbo);" to the code before setting the datasource, the problem goes away.
I've found the cause...
I took out the cbo.Datasource = null line.. and added a cbo.Invalidate() at the end. This has solved the problem.
Thanks all for the advice.
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Now before setting cbo.SelectedValue, or relying on Items to be up-to-date, call
cbo.CreateControl ;
and Items will be re-calculated.
The problem is that SelectedValue/SelectedIndex, which are WinForms properties, only accept the values that are legal according to the Items list, but that one is built only after GUI interaction, i.e. after instantiating a "real" Windows GUI combo box, i.e. after obtaining a Windows handle for the combobox.
CreateControl forces the creation of the Windows handle, no matter what.
ComboBox cbNew = new ComboBox();
cbNew.Name = "cbLine" + (i+1);
cbNew.Size = cbLine1.Size;
cbNew.Location = new Point(cbLine1.Location.X, cbLine1.Location.Y + 26*i);
cbNew.Enabled = false;
cbNew.DropDownStyle = ComboBoxStyle.DropDownList;
cbNew.DataSource = DBLayer.GetTeams(lineName).Tables[0];
cbNew.DisplayMember = "teamdesc";
cbNew.ValueMember = "id";
Console.WriteLine("ComboBox {0}, itemcount={1}", cbNew.Name, cbNew.Items.Count);
// The output displays itemcount = 0 for run-time created controls
// and >0 for controls created at design-time
gbLines.Controls.Add(cbNew);
TO
ComboBox cbNew = new ComboBox();
cbNew.Name = "cbLine" + (i+1);
cbNew.Size = cbLine1.Size;
cbNew.Location = new Point(cbLine1.Location.X, cbLine1.Location.Y + 26*i);
cbNew.Enabled = false;
cbNew.DropDownStyle = ComboBoxStyle.DropDownList;
Console.WriteLine("ComboBox {0}, itemcount={1}", cbNew.Name, cbNew.Items.Count);
// The output displays itemcount = 0 for run-time created controls
// and >0 for controls created at design-time
gbLines.Controls.Add(cbNew);
cbNew.DataSource = DBLayer.GetTeams(lineName).Tables[0];
cbNew.DisplayMember = "teamdesc";
cbNew.ValueMember = "id";
The DataSource, DisplayMember and ValueMember property must be set after the control has been added to its container.
By adding "this.Controls.Add(cbo);" to the code before setting the datasource, the problem goes away.
//Create dynamic combobox and add to Panel
ComboBox ddCombo = new ComboBox();
controls = new Control[1] { ddCombo };
panel.Controls.AddRange(controls);
//After creating add to table layout
tableLayoutPanel.Controls.Add(panel, 0, 0);
ddCombo .Name = "ddName";
ddCombo .Width = 200;
ddCombo .Location = new Point(x, y); ddCombo .DataSource = ds;//or any List
ddCombo .SelectedIndex = ddCombo .Items.Count - 1;
Just to clarify are you calling the count() method
After calling the databind() method
This code produces 2 in the message box for me, can you try it and see how it behaves for you?
You can paste it into a console application, and add a reference to System.Windows.Forms and System.Drawing.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
namespace SO887803
{
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
}
public partial class MainForm : Form
{
private Button _Button;
private ComboBox _ComboBox;
public MainForm()
{
_Button = new Button();
_Button.Text = "Test";
_Button.Location = new Point(8, 8);
_Button.Click += _Button_Click;
Controls.Add(_Button);
_ComboBox = new ComboBox();
_ComboBox.Location = new Point(8, 40);
Controls.Add(_ComboBox);
}
private void _Button_Click(object sender, EventArgs e)
{
List<Item> items = new List<Item>();
items.Add(new Item("A", "a"));
items.Add(new Item("B", "b"));
_ComboBox.DataSource = null;
_ComboBox.DataSource = items;
_ComboBox.DisplayMember = "Title";
_ComboBox.ValueMember = "Value";
MessageBox.Show("count: " + _ComboBox.Items.Count);
}
public class Item
{
public String Title { get; set; }
public String Value { get; set; }
public Item(String title, String value)
{
Title = title;
Value = value;
}
}
}
}
comboBox1.DataSource=somelist;
int c1=comboBox1.DataSource.Count; // still zero
BindingContext dummy = this.comboBox1.BindingContext;// Force update NOW!
int c2=comboBox1.DataSource.Count; // now it equals somelist.Count
I had the same problem (Im working with VS 2005).
What you need to do is set the DataSource to null, clear the items, reassign the datasource , display and value members.
Eg
cbo.DataSource = null;
cbo.Items.Clear();
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Old thread, but I tried some of these solutions, along with suspending/resuming the bindingcontext, binding to and resetting a binding source, and just plain reloading the form. None worked to update my control with the newly bound data at the time of my .datasource setting (my items.count was empty, just like the OP).
Then I realized that my combobox was on a tabpage that was getting removed at the start of the code, and later re-added (after my databinding). The binding event did not occur until the tabpage was re-added.
Seems obvious in retrospect, but it was very difficult to detect at runtime, due to the order of calls and inability to see when things were changing.
Try this code.
cbo.BindingContext = new BindingContext();
cbo.DataSource = null;
cbo.DataSource = cbos;
cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
Maybe your ComboBox`s BindingContext is null.
Ba salam,
you can simply refresh the UI by preformLayout() function;
Example:
comboBox1.performLayout();
regards
mohsen s
please try this:
cbo.Parent = <your panel control>;
cbo.DataSource = null;
cbo.DataSource = cbos; cbo.DisplayMember = "Title";
cbo.ValueMember = "Value";
MessageBox.Show(string.Format("itemcount is {0}", cbo.Items.Count);
I think your question sames like I met today.

Categories

Resources