14

I am using WPF Toolkit Datagrid in one of the applications I am working on. What I want is to store the column width and displayindex as a user preference. I have achived it for column displayindex but for resize I could not find any event on the datagrid which will trigger after column size change. I have tried the "SizeChanged" event which I guess is only fired when it is initially calculating the size and that too is for the whole datagrid and not for the individual columns.
Any alternate solution or if anybody knows about the event ?

Chad La Guardia
  • 5,088
  • 4
  • 24
  • 35
Pravin
  • 650
  • 1
  • 7
  • 17

4 Answers4

11

taken from... :

http://forums.silverlight.net/post/602788.aspx

after load :

    PropertyDescriptor pd = DependencyPropertyDescriptor
                             .FromProperty(DataGridColumn.ActualWidthProperty,
                                           typeof(DataGridColumn));

        foreach (DataGridColumn column in Columns) {
                //Add a listener for this column's width
                pd.AddValueChanged(column, 
                                   new EventHandler(ColumnWidthPropertyChanged));
        }

2 methods:

    private bool _columnWidthChanging;
    private bool _handlerAdded;
    private void ColumnWidthPropertyChanged(object sender, EventArgs e)
    {
        // listen for when the mouse is released
        _columnWidthChanging = true;
        if (!_handlerAdded && sender != null)
        {
            _handlerAdded = true;  /* only add this once */
            Mouse.AddPreviewMouseUpHandler(this, BaseDataGrid_MouseLeftButtonUp);
        }
    }

    void BaseDataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (_columnWidthChanging) {
            _columnWidthChanging = false;
          // save settings, etc

        }

        if(_handlerAdded)  /* remove the handler we added earlier */
        {
             _handlerAdded = false;
             Mouse.RemovePreviewMouseUpHandler(this, BaseDataGrid_MouseLeftButtonUp);
        }
    }

The ColumnWidthPropertyChanged fires constantly while the user drags the width around. Adding the PreviewMouseUp handler lets you process when the user is done.

J...
  • 30,968
  • 6
  • 66
  • 143
  • It doesn't work if we use double click. Double click sets "auto" column width. – Rover May 24 '12 at 06:39
  • 1
    @Rover ...but double click has an easy event to catch. I don't see what the problem is. – J... May 24 '12 at 08:56
  • One problem is that you add a lot of eventhandlers – stefan Jun 03 '16 at 15:00
  • then how to get the new width of the column? – Carlos Liu Jun 27 '17 at 09:36
  • This causes memory leak hell. Also the Mouse up event will fire thousands of times. – Mateusz Myślak Feb 03 '20 at 11:55
  • @MateuszMyślak Well, this is an old question... anyway, I've edited the code. It's pretty easy to add the handler only once, and remove it afterwards. – J... Feb 03 '20 at 13:44
  • @J... Still, AddValueChanged can lead to serious memory leaks. – Mateusz Myślak Feb 04 '20 at 14:31
  • @MateuszMyślak Well, obviously you have to remove the handlers also. I haven't shown that code, but we can assume that part is obvious. If that's not what you're talking about, please do explain where this memory leak comes from. – J... Feb 04 '20 at 14:46
  • @J...Its not that obvious. It's not a standard event handler which can be ignored in some cases. This is an event handler to the object stored in the static cache, which will never be collected by the GC. – Mateusz Myślak Feb 05 '20 at 17:32
1

LayoutUpdated?

I'm working in Silverlight, and the grid is rebound/refreshed every second.

I'm using the LayoutUpdated method, which fires for every layout updating event.

You could keep a dictionary of the column widths and check for deltas. Then you would know which column(s) had changed.

foreach (DataGridColumn column in dataGrid1.Columns)
{
    // check for changes...
    // save the column.Width property to a dictionary...
}
arachnode.net
  • 791
  • 5
  • 12
0

You could try extending DataGrid and then implementing a NotifyPropertyChange event. Something like this:

class MyDataGrid : DataGrid, INotifyPropertyChanged
{
    private DataGridLength _columnWidth;
    public DataGridLength ColumnWidth
    {
        get { return _columnWidth; }
        set
        {
            _columnWidth = value;
            NotifyPropertyChanged("ColumnWidth");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

From there, you can add a delagate to the handler to do whatever you want it to do. Something like:

MyDataGrid dataGrid;
//init grid, do stuff

dataGrid.PropertyChanged += new PropertyChangedEventHandler(ColumnWidthChanged);
//ColumnWidthChanged will be a method you define

Now that you have the delagate, you can define what you want to happen when the column width is changed:

private void ColumnWidthChanged(object sender, PropertyChangedEventArgs args)
{
    if(args.PropertyName.Equals("ColumnWidth"))
    {
        //Do stuff now that the width is changed
    }
}

You'll notice that I'm checking for which property was changed. The way I set it up is such that you can extend other properties and make handlers for their change as well. If you want more then one handler, it would probably be best to make a DataGridPropertyChanged method that switches on which property was changed. It would then call the appropriate method (such as ColumnWidthChanged) for each property that gets changed. That way, you wont have to be checking that each handler only modifies one property.

You didn't specify a language, so I re-tagged this to C#. However, it should be simple enough to transpose to VB if that's what you're using.

Hope this helps!

Chad La Guardia
  • 5,088
  • 4
  • 24
  • 35
  • This doesn't really help because you've only got a single column width and your event will only get raised if the column was resized in code, something you could trap anyway. – MikeKulls Nov 25 '11 at 02:40
0

I assume you want to save the column widths so that the next time the application is started those same column widths are used to generate the data grid.

If that's the case then an alternative is to save the column widths (and indexes) when the application is closing, which would also be more efficient than saving the widths every time a column is resized.

Depending on how your application is structured, something like this should work...

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
  foreach (DataGridColumn column in dataGrid1.Columns)
  {
    // save the column.Width property to a user setting/file/registry/etc...
    // optionally save the displayindex as well...
  }
} 
JayP
  • 809
  • 7
  • 9
  • Hi, can you please give me some clue on how to copy the value from c# to xaml? I have tried this: Dictionary list = new Dictionary(); foreach (DataGridColumn column in DataGridView.Columns) { DataGridLength x = column.Width; list.Add(column.Header.ToString(), x); } – user1850936 Nov 27 '14 at 08:05