Anjitha
Anjitha

Reputation: 85

Reordering DatagridViews Columns and Saving the new Position Programmatically

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

Answers (3)

Martin Verjans
Martin Verjans

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

Mitja
Mitja

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

Sruthi Suresh
Sruthi Suresh

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

Related Questions