Reputation: 85
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.
Upvotes: 4
Views: 3158
Reputation: 4806
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
}
Upvotes: 3
Reputation: 873
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.
Upvotes: 1
Reputation: 697
This May Help you
public partial class Form1 : Form {
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
m_Grid.AllowUserToOrderColumns = true;
SetDisplayOrder();
}
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
CacheDisplayOrder();
}
private void CacheDisplayOrder()
{
IsolatedStorageFile isoFile =
IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream isoStream = new
IsolatedStorageFileStream("DisplayCache", FileMode.Create,
isoFile))
{
int[] displayIndices =new int[m_Grid.ColumnCount];
for (int i = 0; i < m_Grid.ColumnCount; i++)
{
displayIndices[i] = m_Grid.Columns[i].DisplayIndex;
}
XmlSerializer ser = new XmlSerializer(typeof(int[]));
ser.Serialize(isoStream,displayIndices);
}
}
private void SetDisplayOrder()
{
IsolatedStorageFile isoFile =
IsolatedStorageFile.GetUserStoreForAssembly();
string[] fileNames = isoFile.GetFileNames("*");
bool found = false;
foreach (string fileName in fileNames)
{
if (fileName == "DisplayCache")
found = true;
}
if (!found)
return;
using (IsolatedStorageFileStream isoStream = new
IsolatedStorageFileStream("DisplayCache", FileMode.Open,
isoFile))
{
try
{
XmlSerializer ser = new XmlSerializer(typeof(int[]));
int[] displayIndicies =
(int[])ser.Deserialize(isoStream);
for (int i = 0; i < displayIndicies.Length; i++)
{
m_Grid.Columns[i].DisplayIndex = displayIndicies[i];
}
}
catch { }
}
}
}
Upvotes: 1