I have a datagridview in my Windows form.I need to allow the users to reorder the columns and then save the changes permanantly.I set myGrid.AllowUserToOrderColumns = true; But this only changes the display index on design only.
Maybe an old question but I figured out something I would consider simpler.
First, at the begining of your form class, add the following fields :
public partial class MyForm : Form
{
//So whenever you change the filename, you write it once,
//everyone will be updated
private const string ColumnOrderFileName = "ColumnOrder.bin";
//To prevent saving the data when we don't want to
private bool refreshing = false;
... // the rest of your class
Then, attach to the event ColumnDisplayIndexChanged
with the following mehtod :
private void MyDataGridView_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
//Because when creating the DataGridView,
//this event will be raised many times and we don't want to save that
if (refreshing)
return;
//We make a dictionary to save each column order along with its name
Dictionary<string, int> order = new Dictionary<string, int>();
foreach (DataGridViewColumn c in dgvInterros.Columns)
{
order.Add(c.Name, c.DisplayIndex);
}
//Then we save this dictionary
//Note that you can do whatever you want with it...
using (FileStream fs = new FileStream(ColumnOrderFileName, FileMode.Create))
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, order);
}
}
Then comes the OrderColumns method :
private void OrderColumns()
{
//Will happen the first time you launch the application,
// or whenever the file is deleted.
if (!File.Exists(ColumnOrderFileName))
return;
using (FileStream fs = new FileStream(ColumnOrderFileName, FileMode.Open))
{
IFormatter formatter = new BinaryFormatter();
Dictionary<string, int> order = (Dictionary<string, int>)formatter.Deserialize(fs);
//Now that the file is open, we run through columns and reorder them
foreach (DataGridViewColumn c in MyDataGridView.Columns)
{
//If columns were added between two versions, we don't bother with it
if (order.ContainsKey(c.Name))
{
c.DisplayIndex = order[c.Name];
}
}
}
}
And finally, when you fill your DataGridView :
private void FillDataGridView()
{
refreshing = true; //To prevent data saving while generating the columns
... //Fill you DataGridView here
OrderColumns(); //Reorder the column from the file
refreshing = false; //Then enable data saving when user will change the order
}
Entity:
public class Customer : INotifyPropertyChanged
{
string _firstname = "";
public string Firstname
{
get { return _firstname; }
set { _firstname = value; OnPropertyChanged("Firstname"); }
}
string _lastname = "";
public string Lastname
{
get { return _lastname; }
set { _lastname = value; OnPropertyChanged("Lastname"); }
}
int _age = 0;
public int Age
{
get { return _age; }
set { _age = value; OnPropertyChanged("Age"); }
}
public Customer()
{
}
protected void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(name));
}
public event PropertyChangedEventHandler PropertyChanged;
}
The serializable Proxy:
[Serializable]
public class DataGridViewColumnProxy
{
string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
int _index;
public int Index
{
get { return _index; }
set { _index = value; }
}
public DataGridViewColumnProxy(DataGridViewColumn column)
{
this._name = column.DataPropertyName;
this._index = column.DisplayIndex;
}
public DataGridViewColumnProxy()
{
}
}
[Serializable]
public class DataGridViewColumnCollectionProxy
{
List<DataGridViewColumnProxy> _columns = new List<DataGridViewColumnProxy>();
public List<DataGridViewColumnProxy> Columns
{
get { return _columns; }
set { _columns = value; }
}
public DataGridViewColumnCollectionProxy(DataGridViewColumnCollection columnCollection)
{
foreach (var col in columnCollection)
{
if (col is DataGridViewColumn)
_columns.Add(new DataGridViewColumnProxy((DataGridViewColumn)col));
}
}
public DataGridViewColumnCollectionProxy()
{
}
public void SetColumnOrder(DataGridViewColumnCollection columnCollection)
{
foreach (var col in columnCollection)
if (col is DataGridViewColumn)
{
DataGridViewColumn column = (DataGridViewColumn)col;
DataGridViewColumnProxy proxy = this._columns.FirstOrDefault(p => p.Name == column.DataPropertyName);
if (proxy != null)
column.DisplayIndex = proxy.Index;
}
}
}
My Form1 for testing:
public partial class Form1 : Form
{
BindingSource _customers = GetCustomerList();
public BindingSource Customers
{
get { return _customers; }
set { _customers = value; }
}
public Form1()
{
InitializeComponent();
dataGridView1.DataSource = Customers;
LoadDataGridOrderFromFile("myDataGrid.xml", dataGridView1.Columns);
}
private static BindingSource GetCustomerList()
{
BindingSource customers = new BindingSource();
customers.Add(new Customer() { Firstname = "John", Lastname = "Doe", Age = 28 });
customers.Add(new Customer() { Firstname = "Joanne", Lastname = "Doe", Age = 25 });
return customers;
}
static object fileAccessLock = new object();
private static void SaveDataGridOrderToFile(string path, DataGridViewColumnCollection colCollection)
{
lock (fileAccessLock)
using (FileStream fs = new FileStream(path, FileMode.Create))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DataGridViewColumnCollectionProxy));
xmlSerializer.Serialize(fs, new DataGridViewColumnCollectionProxy(colCollection));
}
}
private static void LoadDataGridOrderFromFile(string path, DataGridViewColumnCollection colCollection)
{
if (File.Exists(path))
{
lock (fileAccessLock)
using (FileStream fs = new FileStream(path, FileMode.Open))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DataGridViewColumnCollectionProxy));
DataGridViewColumnCollectionProxy proxy = (DataGridViewColumnCollectionProxy)xmlSerializer.Deserialize(fs);
proxy.SetColumnOrder(colCollection);
}
}
}
private void dataGridView1_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
SaveDataGridOrderToFile("myDataGrid.xml", dataGridView1.Columns);
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.ColumnDisplayIndexChanged +=dataGridView1_ColumnDisplayIndexChanged;
}
}
It will save the DataPropertyName and the DisplayIndex into a xml file. You can extend / modify it easily where your data have to be stored by implementing your custom save and load methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With