This project has moved. For the latest updates, please go here.

DataGridControl AutoCreateColumns Auto-Size Columns

May 9 at 4:29 AM
I'm using DataGridControl with AutoCreateColumns = true and ItemsSource Bound to an ObservableCollection<MyItemViewModel>. The Column widths generated are just a little narrower than what they need to be (even for the initially visible items). When I Bind the same Property to a .NET DataGrid's ItemsSource, all the Columns are auto-sized appropriately to just fit the widest values. How do I get the Column widths to auto-size. I've tried calling GetFittedWidth in the DataGridControl.ItemsSourceChangeCompleted Event (to use it to set Column.Width), it's returning -1. I've commented on a Xceed.Com Forum post (started 9/11/08 on this topic at "https://xceed.com/forums/topic/Column-autosize-to-content/") saying the last 3 Links posted as possible answers are broken, but I've not received a response.
Developer
May 9 at 7:44 PM
Hi,

You can call the column.GetFittedWidth() once the Grid is loaded. So the DataGridControl_Loaded handler is a good place.
But this column.GetFittedWidth() method call will return the fitted width of the columnManagerCell, not its content.

If you want to have the widest visible value for a column, you must use a Dispatcher to call GetFittedWidth() in the Loaded event :
  private void DataGridControl_Loaded( object sender, RoutedEventArgs e )
    {
      var grid = sender as DataGridControl;

      this.Dispatcher.Invoke( DispatcherPriority.ApplicationIdle, new Action( delegate ()
      {
        foreach( Column column in grid.Columns )
        {
          double width = column.GetFittedWidth();
          if( width > 0 )
            column.Width = width;
        }
      } ) );
    }
――――
Get more controls, features, updates and technical support with Xceed Toolkit Plus for WPF
May 9 at 8:22 PM
I tried that code separately from both the DataGridControl's Loaded and ItemsSourceChangeCompleted Event's Handlers and both times, GetFittedWidth returns -1 for all Columns.

FYI:

a. I was incorrect when I said that the "Column widths generated are just a little narrower than what they need to be". Actually, the Width and ActualWidth are both 125 for all Columns. I'm using AutoCreateColumns so I have no Columns explicitly defined in XAML or Code-Behind, so I don't know where it's getting 125 from. There's still plenty of width left in its Parent Element, so it's not anywhere close to an even divisor of the Parent Element's Actual Width.

b. Also, note that prior to the App being idle after start up, as I'm applying default values of filters, I call several times, the Setter of the ObservableCollection<MyGridItemViewModel>Source Property Bound to the DataGridControl's ItemsSource.
Developer
May 9 at 9:02 PM
Hi,

Using the Loaded event to call column.GetFittedWidth() through a dispatcher works as expected in Toolkit v3.0 and up.
Here's my complete sample :
<Window x:Class="WpfApplication118.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication118"
        mc:Ignorable="d"
        xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
    <xcdg:DataGridControl ItemsSource="{Binding}" 
                          Loaded="DataGridControl_Loaded"
                          AutoCreateColumns="True" />
  </Grid>
</Window>
 public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();

      this.DataContext = new ObservableCollection<MyItemViewModel>()
      {
        new MyItemViewModel() { ID = 1, FirstName = "Brian the top Jones", Birthday = DateTime.Now },
        new MyItemViewModel() { ID = 10, FirstName = "Michael the great one", Birthday = DateTime.Now },
        new MyItemViewModel() { ID = 100, FirstName = "Tom the coolest QB on earth", Birthday = DateTime.Now },
        new MyItemViewModel() { ID = 1000, FirstName = "Mark Fitzpatrickeneski von Guarted", Birthday = DateTime.Now },
      };

    }

    private void DataGridControl_Loaded( object sender, RoutedEventArgs e )
    {
      var grid = sender as DataGridControl;

      this.Dispatcher.Invoke( DispatcherPriority.ApplicationIdle, new Action( delegate ()
      {
        foreach( Column column in grid.Columns )
        {
          double width = column.GetFittedWidth();
          if( width > 0 )
            column.Width = width;
        }
      } ) );
    }
  }

  public class MyItemViewModel
  {
    public int ID
    {
      get;
      set;
    }

    public string FirstName
    {
      get;
      set;
    }

    public DateTime Birthday
    {
      get;
      set;
    }
  }
a) 125 is the default column's width

b) Can you submit a complete sample if it's still not working for you ?
Thanks.

――――
Get more controls, features, updates and technical support with Xceed Toolkit Plus for WPF
May 10 at 12:24 AM
Edited May 10 at 12:25 AM
  1. Re. 125 is the default column's width: Ok.
  2. In the Application's Startup Event Handler in App.Xaml.Cs, I create (and assign to the Window's DataContext) the View Model Instance and then call Window's Show Method. If I don't change DataGridControl's ItemsSource, then the above workaround code works. However, if I assign a new value to DataGridControl's ItemsSource's Bound / Source Property after that (i.e. to apply changes to grid item filters the user specifies via other Elements), then the Columns return to their default width (of 125). In my test app, if I add the workaround code to ItemsSourceChangeCompleted Event Handler also, then it'll work even after the ItemsSource change.
  3. However, in my production app, like I said, even though I'd placed the workaround code in both the DataGridControl's Loaded and ItemsSourceChangeCompleted Event's Handlers, GetFittedWidth still returns -1 for all Columns. I did just notice a new clue which explains the immediate symptom of why GetFittedWidth returns -1, but it doesn't explain the root cause. In both those Event Handlers, the DataGridControl's Items Collection has a 0 Count. I can't explain why that is though. From code review and the final U.I. display, there are > 0 Items. Even if Items were (for some currently unknown reason empty) at some point, one would expect that the Event Handlers would eventually be called with a non-empty Items.
  4. Why is this workaround code even necessary??? Like I said, with .NET DataGrid, the Columns are auto-sized without any such extra code, and it does so in my same production app with its ItemsSource Bound to the same Property that my DataGridControl is Bound to. I would consider this a bug / feature omission. 3rd party tools should extend and add features not drop them vs. the standard tools.
Developer
May 10 at 1:40 PM
Hi,
  1. I was doing the workaround in the Loaded event, which is called only once, so if you change the DataGridControl.ItemsSource, you also need to add the workaround in ItemsSourceChangeCompleted event handler...as you do.
  2. If the sample application is working but the production application is not, there must be something you do in the production application that is different. You should try to see when the items are added to the DatagridControl and do the workaround at that moment. Its like if your production app is postponing the items addition into the DataGridControl.
  3. The workaround is necessary because the DataGridControl is using a BeginInit()/EndInit() initialization, which occurs slightly after the Loaded event.
    The DataGridControl is the only WPF datagrid that provides a rich, fluid and high performance user experience. It includes an advanced smooth scrolling and zero-lag data virtualization.
    Lets say you have 100 000 items in the DatagridControl, only the visible ones will be processed and displayed. The others will be virtualized. The DataGridControl includes special algorithms to enabled a fast scrolling with this special virtualization. Even if you set a fitted Width for columns, after scrolling to the 50 000th item, you may end up with not fitted columns since you measured them a while ago. Same thing if you group and the visible items are modified.
    We do not want to slow down the process by calculating the width of all visible cells at each scrolling/grouping/sorting/other option. We do not know the size of each cell from the 100 000 items. So a default width of 125 is used, and you can set the width you want for every column if its not good for you.
――――
Get more controls, features, updates and technical support with Xceed Toolkit Plus for WPF
May 10 at 6:32 PM
Re. Ok.

Re. 2: Actually, I did some more testing, and as expected, there were subsequent calls to the ItemsSourceChangeCompleted Event Handler where the DataGridControl's Items Collection was not empty. However, even then, GetFittedWidth returns -1. My production app assigns an empty Collection to the ObservableCollection<MyItemViewModel> Property in the View Model when it's Instantiated which is done so before it's first assigned to the DataGridControl's DataContext (which btw, unexpectedly to me, did not Raise ItemsSourceChangeCompleted). Then, when the Window's Show Method is called, strangely, now the DataGridControl's ItemsSourceChangeCompleted Event Handler is finally called (during which Items is empty and GetFittedWidth returns -1) and (subsequently as expected) the Loaded Event Handler is called (during which Items is still empty but GetFittedWidth now return values > 0). However, after Window's Show Method is called, I then assign a non-empty Collection to the Property Bound to ItemsSource which leads to the ItemsSourceChangeCompleted Event Handler being called (during which now Items is not empty but GetFittedWidth still returns -1). So, the 2 Event Handlers are working / not working in the opposite ways in my production app vs. my test app. Sigh.

Re. 3: Ok.
May 18 at 5:29 PM
Could I get a reply to #2 please? I'm hoping that additional symptom info might help you answer the question, provide a work-around, suggest more investigation techniques, etc.
Developer
May 19 at 1:57 PM
Hi,

Can you build a test app which reproduce your production app ? It will be easier to have the same thing as you instead of having to create a program which could be different than yours.
Thanks.

――――
Get more controls, features, updates and technical support with Xceed Toolkit Plus for WPF