This is the first time I've tried to use comboboxcolumn in a datagridview (WinForms, C#, EF4).
With the designer, I created a datagridview to show the orders table, and inside the datagrid a comboboxcolumn to show the customer names from the customers table, this column has now the properties below:
Data:
DataPropertyName: CustomerID
DataSorce: customerBindingSource
DisplayMember: CompanyName
ValueMember: CustomerID
Design:
(Name): Cbo
ColumnType: DataGridViewComboBoxColumn
Then I entered the next code:
private void Form1_Load(object sender, EventArgs e)
{
nw = new NorthwindEntities();
testBindingSource.DataSource = nw.Orders;
}
When run the project, got the error message: "datagridviewcombocell is not a valid value".
Please is there any advice on this, is there anything missing?
Related
I had a DataGrid which contains columns quantity price and total.
When I add one product it will have a price fetched from db say Rs.100
I give quantity as 5 so total will be 500.
When I add other product having price Rs.150 and I give quantity as 4 total will be 600.
These all things happening in GridView and the grant total(textbox outside) will be calculating sum of total(gridview total) ie 500+600=1100
I need that 1100 or whatever when I change the quantity in the DataGridView itself..
Here am not using DataGrid template column for quantity am using only DataGridTextBox columns.
1st possible solution: you can trigger the re-calculation method when the content of the cell has changed, that would be something like that:
XAML:
<DataGrid x:Name="yourGrid" CurrentCellChanged="yourGrid_CurrentCellChanged" ...>
And your code behind file implements:
private void yourGrid_CurrentCellChanged(object sender, EventArgs e)
{
calculate_grand_total(); // of course you have to replace that with your appropriate method name
}
2nd possible solution: I don't know anything about your data source binding details since your question does not contain information about that - but your choose a ObservableCollection as data source, in this example a collection of JTestStep objects
tSteps = new ObservableCollection<JTestStep>();
then you can trigger actions upon a change of the collection:
tSteps.CollectionChanged += new NotifyCollectionChangedEventHandler(DataGrid_CollectionChanged);
and do your recalculation in that case:
private void DataGrid_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
calculate_grand_total();
}
Most WPF/EF tutorials only cover databinding in one window. However, in reality data gets displayed across many windows. You often display a record in the first window and dig deeper in related details in the next windows.
So, this also is the case in my scenario. Here you can see my data structure and the ui. Actually I am not dealing with Customers and Invoices, but the structure is the same. (My concrete questions are at the very end.)
In the InvoicesWindow I can select an Invoice and press "Show Invoice". That opens a CustomerWindow displaying Customer details and his invoices. The right invoice is pre-selected. To each Invoice displayed in the CustomerWindow I can add Items or edit them. This is done in a seperated window called "ItemWindow". Editing the DataGrids is not an option. They are set to ReadOnly.
Here is the code of the wpf-window classes (I only have done displaying data yet, not saving):
Invoices Window:
public partial class InvoicesWindow : Window
{
private MyEntities context = new MyEntities();
public InvoicesWindow ()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CollectionViewSource invoicesViewSource = (CollectionViewSource)FindResource("invoicesViewSource");
invoicesViewSource.Source = context.Invoices;
}
private void ShowInvoice_Click(object sender, RoutedEventArgs e)
{
Invoice selectedInvoice = (Invoice)InvoicesDataGrid.SelectedItem;
var customerWindow = new CustomerWindow(selectedInvoice);
customerWindow.ShowDialog();
}
}
Customer Window:
public partial class CustomerWindow : Window
{
private MyEntities context = new MyEntities();
private Invoice selectedInvoice;
public CustomerWindow()
{
InitializeComponent();
}
public CustomerWindow (Invoice selectedInvoice)
{
InitializeComponent();
this.selectedInvoice = selectedInvoice;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Set the data
CollectionViewSource customerViewSource = (CollectionViewSource)FindResource("customerViewSource ");
customerViewSource.Source = context.Customers.Where(p => p.id == selectedInvoice.Customer.id);
//Select the right invoice
CollectionViewSource customerInvoicesViewSource = (CollectionViewSource)FindResource("customerInvoicesViewSource ");
customerInvoicesViewSource.Items.MoveCurrentTo(((ObjectSet<Invoice>)customerInvoicesViewSource.Source).Where(p => p.id == selectedInvoice.id).SingleOrDefault());
}
private void EditItem_Click(object sender, RoutedEventArgs e)
{
Item selectedItem = (Item)ItemsDataGrid.SelectedItem;
var itemWindow = new ItemWindow((IQueryable<Customer>)(customerViewSource.Source),selectedInvoice,selectedItem);
itemWindow.ShowDialog();
}
}
Item window:
public partial class ItemWindow : Window
{
private Invoice _selectedInvoice;
private Invoice _selectedItem;
private IQueryable<Customer> _customers;
public ItemWindo()
{
InitializeComponent();
}
public ItemWindow(IQueryable<Customer> customers, Invoice selectedInvoice, Item selectedItem)
{
InitializeComponent();
this._customers = customers;
this._selectedInvoice = selectedInvoice;
this._selectedItem = selectedItem;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Set the data
CollectionViewSource customerViewSource = (CollectionViewSource)FindResource("customerViewSource");
invoicesViewSource.Source = _customers;
//Select the right invoice
CollectionViewSource customerInvoicesViewSource = (CollectionViewSource)FindResource("customerInvoicesViewSource ");
customerInvoicesViewSource.Items.MoveCurrentTo(_selectedInvoice);
//Select the right item
CollectionViewSource customerInvoicesItemsViewSource = (CollectionViewSource)FindResource("customerInvoicesItems");
customerInvoicesItems.Items.MoveCurrentTo(_selectedItem);
}
}
I wrote the code out of my mind. So, maybe some casts are missing and some methods are mis-spelled. I hope I got the right type with "ObjectSet", it also could be "ObjectCollection" or something like that.
The XAML was created widely with assistance of VS2010 like in this video: http://msdn.microsoft.com/de-de/data/ff806174.aspx
So, finally my questions ;)
Is the design of binding I applied correct?
In CustomerWindow I create a new context.
Between CustomerWindow and ItemWindow I just pass the data of the same context and select the current item manually.
In CustomerWindow I use a ObjectSet (or ObjectCollection, I'm not sure about the type anymore) with a single entry as Source for the customersCollectionViewSource. This works fine. However, there is no need for a collection, because I only edit a single Customer. I did not manage to set a single Customer as Source. I didn't know how to adjust the view source which was generated by VS2010.
I haven't done saving yet. But I think I am going to run into problems due to my design between CustomerWindow and ItemWindow. Maybe you can give me some advice here.
When the "Apply"-Button in ItemWindow gets pressed, the Item data should be updated in DB. But not the Customer- and Invoices-related data in the CustomerWindow underneath.
The DataGrid of Items in CustomerWindow should get updated, when closing the ItemWindow. But not the rest of the fields in the CustomerWindow, since here could have been data changed before opening the ItemWindow.
The only solution for me to overcome that "synchronisation problem": The User is forced to press "Apply" in the CustomerWindow before he can press the "New Item" or "Edit Item", if there have been any changes. (Kinda like the "window resolution control" of windows 7 when working with two monitors) But this is not too user friendly.
A cleaner design would be to use the MVVM design pattern.
Inject the view model into the window's context and bind the view model to either a collection of entities or a single entity, bind in the xaml to properties in the view model(s) and use commands implemented in the view model for actions e.g. add new, delete.
The windows shouldn't be aware of the context.
If you have a list view model + window and a details window (preferably with a view model), then the list view model should pass the selected item to the details view model (or window) as the context.
If the windows are not open at the same time or do not have related objects, then their views models should not share a database context, otherwise, in order for the changes to be reflected easily between the windows, they will have to share the database context.
I'm binding a datagrid to a DataView. I would like to hide the ID column when the data is displayed. The ID column needs to exist in the data as it is used in another part of my code.
The ID column is always the first (index 0) column.
Am I right in thinking that the DataContextChanged event doesn't guarantee that all columns have been refreshed?
How can I ensure that binding has finished before hiding the column? Ideally, I would like to hide it by its column name.
EDIT: Forgot to say that I can't specify the columns in XAML, as they are generated from dynamic SQL.
I figured it out.
In the AutoGeneratingColumn event, I'm checking the DataGridAutoGeneratingColumnEventArgs header value and canceling the operation if it matches the column header.
Private void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.Column.Header.ToString() == "ID")
{
e.Cancel = true;
}
}
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.
I am working on WPF datagrid. I am using auto-generated columns as I am supposed to retrieve data from excel sheet and number of columns are not fixed.
On the celleditending event I am checking whether it is the last column or not. if it is I am adding the new column to datatable and I refresh the ItemsSource of the grid as mentioned below:
private void grdEmployee_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if ((e.Column.DisplayIndex + 1) == empDS.Tables[0].Columns.Count)
{
DataColumn col = new DataColumn((e.Column.DisplayIndex + 1).ToString());
empDS.Tables[0].Columns.Add(col);
grdEmployee.ItemsSource = null;
grdEmployee.ItemsSource = empDS.Tables[0].DefaultView;
grdEmployee.Items.Refresh();
}
}
The problem I am facing is, when I refresh the itemssource, I am losing the data from row which user was editing. Data entered by user is committed to datatable only when user finishes row editing.
Please guide me. If you need any further info please let me know.
Regards,
Priyank