I am working on a c# windows forms project where i have to open all the cells of datagridview in edit mode as soon as it gets focus . But i am unake to find out how to do it . I am new to c# .
CodePudding user response:
By default all cells are already editable. You will have to click twice one for selecting cell and then to edit it or press F2 after selecting cell.
You will have to make sure of following things
- The DataGridView control is enabled.
- The EditMode property value is not EditProgrammatically.
- The ReadOnly properties of the cell, row, column, and control are all set to false.
CodePudding user response:
MVVM
Programmers who are new to programming a DataGridView tend to fiddle with the cells directly when reading and writing values. Although this can work, it is not efficient: your code will be hard to read, hard to debug, hard to change, and hard to debug.
In modern programming, there is a tendency to separate your data (= model), from the way that this data is presented to the operator (= view). An adapter class, often called ViewModel, is used to connect the model to the view. Toggether these three classes are abbreviated MVVM. Consider to read some background information about this.
One of the nice things about separating your model from your view, is that you can change your view without having to change your model: if you want to show your data in a Graph instead of a Table, your data won't have to change. Or if you want to add extra columns to your data, but you don't need to display them, your View won't have to change. Similarly: if you plan to fetch the data from a file, instead of a database: no changes in the view.
Other advantages of separating your model from your view, is that you can reuse the model in forms that show other aspects of your data, you can unit test the model without using a form, during development you can mock the model, to show your forms without real data.
MVVM and DataGridView
Alas, you didn't specify what you want to show in your DataGridView, so let's assume you want to show a table of Products
:
Model
class Product
{
public int Id {get; set;}
public string Name {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int StockCount {get; set;}
public int LocationId {get; set;} // foreign key to location
...
}
Of course your Model needs a procedure to fetch the Products that must be shown:
class MyModel
{
IEnumerable<Product> FetchProducts()
{
// TODO implement; out of scope of the question
}
... // other Model methods
}
So in the Model, you won't have methods that have anything to do with how the data is displayed.
ViewModel
Suppose, on this specific form (this view) you don't want to show all Products, you only want to show products that are out-of-stock. This is a typical adapter method to couple your Model to your View
class MyViewModel
{
private MyModel Model => ...
IEnumerable<Product> FetchOutOfStockProducts()
{
return this.Model.FetchProducts()
.Where(product => product.StockCount == 0);
}
}
If in future you don't want to show the Products that are completely out-of-stock, but you also want to show Products that are almost out-of-stock, you will only have to change this procedure (and maybe it's name, for better readability).
If you really want to separate the Model from the View, consider to create a class DisplayedProduct
, which internally holds a Product
. This gives you the opportunity to add or hide properties of Product. In future you can change the Product, without having to change the 20 forms that use the Product. You can create DisplayedProducts that internally use something else than a product. Or if you want to add a property:
public decimal TotalStockValue => this.Product.StockCount * this.Product.Price;
Whether you need to create a DisplayedProduct class depends on how much the displayed data differs from your model, how often you think that the Product will change, how often the Product will be displayed on different forms and how often you expect the View to change.
The View
This is the interesting part. Using Visual Studio designer you have added a DataGridView and columns. You need to tell the DataGridView which column should show which value of the Product.
You can also do this using Visual Studio Designer. If you want to make sure that the compiler will complain if you made a typing error, do something like this in the constructor:
public MyForm()
{
InitializeComponent();
// define which columns should show which properties of Product:
this.columnId.DataPropertyName = nameof(Product.Id);
this.columnName.DataPropertyName = nameof(Product.Name);
this.columnPrice.DataPropertyName = nameof(Product.Price);
... // etc.
Of course you don't need columns for values that you won't show anyway. Another advantage of seperation of model and view: if in future a Property is added to the column that you don't need to show, your code will still work.
Your form also has a property that holds the ViewModel:
private MyViewModel ViewModel => ...
You can fill this in the constructor, or create a new one every time you need it. Which method you'll need depends on how much work it is to create a ViewModel.
To define which Products are shown:
private BindingList<Product> DisplayedProducts
{
get => (BindingList<Product>)this.dataGridViewProduct.DataSource;
set => this.dataGridViewProduct.DataSource = value;
}
Of course your form needs a procedure to display the initial set of Products:
private IEnumerable<Product> FetchInitialProductsToShow()
{
return this.ViewModel.FetchOutOfStockProducts();
}
Now all you have to do to show the Products when your Form is loaded:
private void OnFormLoading(object sender, ...)
{
this.DisplayedProducts = new BindingList<Product>(
this.FetchInitialProductsToShow().ToList());
}
If you allowed it when creating the datagridview, the operator can Add / Remove / Change products. When he is finished making the changes, he can inform you by clicking an Ok, or Apply Now button:
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<Product> editedProducts = this.DisplayedProducts;
// find out which Products are added / removed / changed
this.ProcessEditedProducts(editedProducts);
}
BTW, did you notice, that because I separated the Model from the View, that most procedures in your form are "one-liners"?
Two nice methods: get the current product, and if you allow multiple selection: get all selected products:
private Product CurrentProduct =>
(Product) this.DataGridViewProducts.CurrentRow?.DataBoundItem;
private IEnumerable<Product> SelectedProducts =>
this.DataGridViewProducts.SelectedRows
.Cast<DataGridViewrow>()
.Select(row => row.DataBoundItem)
.Cast<Product>();