ComboBox not displaying items in BindingSource - winforms

I am binding a ComboBox BindingSource and then adding items to the BindingSource. Unfortunately the items don't seem to added to the ComboBox.Items property. What am I missing in the following code?
BindingSource bindingSource;
private List<string> tables;
private void button1_Click(object sender, EventArgs e)
{
string newItemText = "item" + tables.Count;
tables.Add(newItemText); // comboBox1.Items.Count does not increase
}
private void Form1_Load(object sender, EventArgs e)
{
tables = new List<string>();
bindingSource = new BindingSource();
bindingSource.DataSource = tables;
comboBox1.DataSource = bindingSource;
}

List<T> doesn't support change notifications. If you are not going to modify the list after setting the DataSource, List<T> is fine, When you need to view your updates to list immediately use BindingList<T> or ObservableCollection<T> instead.
private BindingList<string> tables = new BindingList<string>();
and you don't need tables = new List<string>(); line in Form1_Load method, you can initialize it at the time of declaration itself.

Related

How to change the string format of a datagrid column in WPF with vb.net programmatically?

Basically, what I want to do is the WinForm Datagridview equivalent of dgvPreview.Columns(4).DefaultCellStyle.Format = "#,##0.00"
But instead of Datagridview, it's with Datagrid in WPF. Best I can do is assign a datatable to a Datagrid and change its alignment property.
DataGridPreview.ItemsSource = dtPreview.DefaultView
Private Sub BtnTest_Click(sender As Object, e As RoutedEventArgs) Handles BtnTest.Click
Dim txt As New DataGridTextColumn()
Dim s As New Style
s.Setters.Add(New Setter(TextBox.TextAlignmentProperty, TextAlignment.Right))
txt.CellStyle = s
DataGridPreview.Columns(4).CellStyle = s
'dgvPreview.Columns(4).DefaultCellStyle.Format = "#,##0.00"
End Sub
Please point me in the right direction. I'm trying to migrate from Winforms to WPF. And as much as possible I want to do this programmatically. I have also tried using the AutoGeneratingColumn but I can't figure it out.
If e.Column.Header.ToString = "Amount" Then
Dim dg As DataGridTextColumn = e.Column
dg.Binding.StringFormat = "#,000.00"
End If
If you are using AutoGeneratingColumn, the best time to update the StringFormat is on AutogeneratingColumn event. Column's binding serves as a blueprint for the individual cells' binding, so for some updates it is important to do them before the cells are created. In C# it will be something like this:
public MainWindow()
{
InitializeComponent();
grid.ItemsSource = Enumerable.Range(0, 10).Select(s => new { Id = s });
}
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
(e.Column as DataGridTextColumn).Binding.StringFormat = "0.000";
}

LINQ DataGridView Insertion Deletion not showed

I've a problem with my DataGrid bound to a LINQ Expression.
I've in fact two DataGrid bound to the same SQL table, using the same DataContext.
When I edit existing rows in one or the other grid, the changes are reflected to the other grid, and vice versa, as expected.
But when I insert a record or delete a record in one of the grid, changes are not reflected to the other grid. It is like new row are in a state where my LINQ expression does not take those type of changes.
I need to save the changes to the Database, before the other grid can "see" the changes.
Is there anyway for both LINQ result object can be notify of the Insert row/Delete row changes?
Here is my code:
public partial class Form1 : Form
{
GMR_DEVEntities CTX;
public Form1()
{
InitializeComponent();
CTX = new GMR_DEVEntities();
dataGridView1.AutoGenerateColumns = true;
dataGridView2.AutoGenerateColumns = true;
this.dataGridView1.Columns.Clear();
this.dataGridView2.Columns.Clear();
}
private void btnLoadGrid1_Click(object sender, EventArgs e)
{
var Data = from dd in CTX.tblConfigs select dd;
this.dataGridView1.DataSource = Data;
}
private void btnLoadGrid2_Click(object sender, EventArgs e)
{
var Data = from dd in CTX.tblConfigs select dd;
this.dataGridView2.DataSource = Data;
}
private void btnSave_Click(object sender, EventArgs e)
{
CTX.SaveChanges();
}
}
I've found a solution, that work good.
The first Grid (dtgGrid )is attach to a BindingSource, witch is attach to a LINQ query result. Then the second grid (dtgFilteredGrid), is attach to another BindindSource witch is the result of LINQ query that filter the first BindingSource. Then when the user edit dtgFilterGrid, update are manually done to keep the the first BindingSource up to date.

How to have separate pages databound?

I'm wanting to use a datasource to go through records but one at a time per page.
So I'd like a whole page to be dedicated to a single record.
How would I do that?
Easiest way is just swap out the DataContext on the page. So don't bind to the list, bind to individual items in list.
private List<Question> _questions = new List<Question>();
private int _currentItem = 0;
private void nextButton_Click(object sender, RoutedEventArgs e)
{
_currentItem++;
this.DataContext = _questions[_currentItem];
}
private void backButton_Click(object sender, RoutedEventArgs e)
{
_currentItem--;
this.DataContext = _questions[_currentItem];
}
Now obviously you would have to add bounds checking to make sure you don't go past the last question, or before the first question, but you get the idea.
If you are using MVVM the idea is pretty much the same - you want the viewmodel to model a single item rather than the list of items, then you just swap the data for that current item as you navigate forward or backwards.

Add a new row to DataGrid at runtime (WPF)

I have a DataGrid and fill it when window loaded, like this:
private void Window_Loaded(object sender, RoutedEventArgs e) {
var list = DbService.GetStuffsFull();
dataGrid.ItemsSource = list;
}
and when i try to add a new row at run-time by this code:
Stuff item = new Stuff();
dataGrid.Items.Add(item);
I get this error:
Operation is not valid while
ItemsSource is in use. Access and
modify elements with
ItemsControl.ItemsSource instead.
how can I add a new row at runtime?
You cannot modify items in Items collection if you provided it as ItemsSource. You should either add item to your list (with INotifyCollectionChanged implemented or you should initially populated Items property via Add method.
The error description is pretty clear, isn't it?
try doing something like this:
var row = dataGrid.NewRow();
dataGrid.Rows.Add(row);
row["column1"] = "data1";
row["column2"] = "data2";
row["column3"] = "data3";
InitializeComponent();

Winforms, Combobox, Databinding... allow user to type in a value not found in the DataSource

Just like the title says... I have a Winforms application with a databound dropdown. I want the user to have the convenience to pick from a bunch of predefined values, but also the ability to type in his own value
If I just enable databinding and set dropdown type to anything but DropDownList, it allows me to enter anything I want, but does not persist it to the objects...
Seems like a simple problem to solve... help?
I've added an event handler on ComboBox.Leave this code would add the newly typed in string in the combobox to the underlying list(countries) as well as refresh the combobox binding to it.
Limitations
You'd have to handle the addition of new element based on the type of datasource you have.
The List.Contains is case sensitive you might want to keep all the strings in one case. And convert the user entered value to that case before deciding to add it to the datasource.
Here you go, modify the comboBox1_Leave eventhandler according to your datatypes and datasource.
public partial class Form1 : Form
{
private List<string> countries;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
countries = new List<string>();
countries.Add("Australia");
countries.Add("Belgium");
countries.Add("Canada");
comboBox1.DataSource = countries;
}
private void comboBox1_Leave(object sender, EventArgs e)
{
ComboBox combo = (sender as ComboBox);
CurrencyManager cm = (combo.BindingContext[combo.DataSource] as CurrencyManager);
if (!cm.List.Contains(combo.Text))
{
cm.List.Add(combo.Text);
cm.EndCurrentEdit();
cm.Refresh();
cm.Position = cm.Count - 1;
}
}
}

Resources