Home Forums WPF controls Xceed DataGrid for WPF BUG: Column.GetFittedWidth() returning -1

Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • User (Old forums)
    Member
    Post count: 23064
    #23301 |

    When the grid is contained within a panel with Visibility=”Collapsed” the Column.GetFittedWidth() method returns -1.

    I have an event handler that automatically resizes all columns to their fitted width whenever the ItemsSource is changed. I have had to disable this for when the grid is collapsed, which means that when it is made visible the columns are all the wrong size.

    Thanks
    Neil

    Imported from legacy forums. Posted by nmosafi (had 10314 views)

    Xceed Support
    Member
    Post count: 5658

    Before assigning the ItemsSource, the datagrid’s UpdateLayout must be called to ensure that the DataGridControl’s template is created and sized correctly in the page or window.

    Imported from legacy forums. Posted by Jenny [Xceed] (had 3418 views)

    User (Old forums)
    Member
    Post count: 23064

    Hmm ok… but I am unsure when to call that method.

    The ItemsSource is bound to a property of type ObservableCollection<>. When the page loads, that property will be null, then when the user presses the “Search” button, that property is set to the collection returned from the search.

    As there is a logical separation between the UI and the commands / data models, I am not sure where and when I can do this.

    Imported from legacy forums. Posted by nmosafi (had 896 views)

    Xceed Support
    Member
    Post count: 5658

    You should call UpdateLayout immediately before setting the ItemsSource property. For example:

    <code>
    protected override void OnInitialized( EventArgs e )
    {
    base.OnInitialized( e );
    DependencyPropertyDescriptor gridItemsSourceDescriptor = DependencyPropertyDescriptor.FromProperty( DataGridControl.ItemsSourceProperty,
    typeof( DataGridControl ) );

    gridItemsSourceDescriptor.AddValueChanged( this.OrdersGrid,
    OnDataGridItemsSourceChanged );
    }
    protected void OnDataGridItemsSourceChanged( object sender, EventArgs args )
    {
    // Before assigning the ItemsSource, UpdateLayout must be called to ensure that the
    // DataGridControl’s template is created and sized correctly in the page or window.
    this.OrdersGrid.UpdateLayout();
    foreach( Column column in this.OrdersGrid.Columns )
    {
    double width = column.GetFittedWidth();
    if( width > -1 )
    {
    column.Width = width;
    }
    }
    }

    private void ChangeDataSource( object sender, RoutedEventArgs e )
    {
    this.OrdersGrid.Columns.Clear();
    this.OrdersGrid.ItemsSource = null;

    this.OrdersGrid.ItemsSource = new DataGridCollectionView( App.Employees.DefaultView );
    }
    </code>

    Imported from legacy forums. Posted by Jenny [Xceed] (had 1225 views)

    User (Old forums)
    Member
    Post count: 23064

    Thanks Jenny but I still get -1 after copying your code?

    Imported from legacy forums. Posted by nmosafi (had 944 views)

    User (Old forums)
    Member
    Post count: 23064

    It might be related to the fact that you DataGrid is contained in a panel that has Visibility=Collapsed.

    The implementation of GetFittedWidth() actually uses the DesiredSize of the first VisualChild of each Cell to compute its value.

    Here are the conditions that can make GetFittedWidth() return -1:

    – There are no Rows in any section of the datagrid (FixedHeaders/Footers, Headers/Footers, DataRows).

    – The VisualTree of the Cells have not been built, most probably because the Cells’ template has not been applied, implying that no layout pass has been run on the Rows/Cells yet.

    Jenny’s proposition of calling UpdateLayout() normally solves the second problem as it forces a layout pass to be run on the datagrid, therefore applying the templates for each sub-component of the datagrid.

    My guess is that when a control is Visibility.Collapsed, layout is inhibited for that control and its children, even when an explicit layout is requested by calling UpdateLayout(). That might explain why you always get -1.

    I’ll leave us both with this hypothesis for now, and will investigate further later today…

    Imported from legacy forums. Posted by Pascal (had 1740 views)

    User (Old forums)
    Member
    Post count: 23064

    Hi Pascal

    I agree – if the visibility is collapsed, there will be no visual content from which to calculate the width. That could cause problems as it works in all other circumstances!

    If you can find a way round it, please let me know.

    Thanks
    Neil

    Imported from legacy forums. Posted by nmosafi (had 1464 views)

    User (Old forums)
    Member
    Post count: 23064

    The only workaround I can think of right now would be to make your panel transition by the “Hidden” state when going from Collapsed to Visible.

    That would allow a layout pass on the DataGrid, therefore making subsequent calls to GetFittedWidth() return the proper information. Since the grid would update its layout while hosted in a Hidden panel, the columns could be set to their proper widths before the panel is made “completely” visible.

    Imported from legacy forums. Posted by Pascal (had 1284 views)

    User (Old forums)
    Member
    Post count: 23064

    This problem also occurs if the grid is Visible, but on a different tab. You have to setfocus to the tab first then autofit the columns.

    OR use the code below. If I have done this a crap way please tell me as I am new to C# WPF

    public class DataGridControl : Xceed.Wpf.DataGrid.DataGridControl
    {

    private bool RunAutoFit = false;

    public DataGridControl() : base()
    {
    this.LayoutUpdated += new EventHandler(Grid_LayoutUpdated);
    }

    private void Grid_LayoutUpdated(object sender, EventArgs e)
    {
    if (this.RunAutoFit)
    {
    AutoFit();
    this.RunAutoFit = false;
    }
    }

    public void AutoFit()
    {
    foreach (Column col in Columns)
    {
    double fittedWidth = col.GetFittedWidth();
    if (fittedWidth > 0) col.Width = fittedWidth + 2;
    }
    }
    }

    Imported from legacy forums. Posted by Matt (had 1135 views)

    User (Old forums)
    Member
    Post count: 23064

    This bit was missing from class

    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
    base.OnItemsSourceChanged(oldValue, newValue);
    if (this.AutoCreateColumns) this.RunAutoFit=true;
    }

    Imported from legacy forums. Posted by Matt (had 1186 views)

    User (Old forums)
    Member
    Post count: 23064

    Is there any update on this. I am using version 1.3 and GetFittedWidth returns -1 despite the UpdateLayout call, and despite the fact that the datagrid, containing grid, and top level window are all “Visible”.

    Is there some other workaround, clean or not, that would make it possible to auto-size columns?

    Imported from legacy forums. Posted by David (had 7276 views)

    User (Old forums)
    Member
    Post count: 23064

    See thread http://xceed.com/CS/forums/permalink/11646/13791/ShowThread.aspx#13791

    Imported from legacy forums. Posted by Diego (had 1188 views)

    User (Old forums)
    Member
    Post count: 23064

    Jenny, I have tried using your code described in your post dated 29/05/2007 2:30 PM, and also the code in the thread at http://xceed.com/CS/forums/permalink/11646/13791/ShowThread.aspx#13791 but I am finding that some of my columns in some of my DataGridControls are returning -1 from GetFittedWidth().  It seems unexplainable why only some of the columns are doing this and why only on some grids.  On one grid, it occurs on all columns after column 5.

    I am binding my grid to an IEnumerable property that returns a list of elements based on fields created from a LINQ to XML query within the property.  The columns are also constructed within the property ‘get’ accessor.  I’m not sure that this is relevant, but it is necessary to do this for other reasons outside of this topic.

    I have also noticed that if I use the code at the abovementioned link, I get the following error during the call to UpdateLayout():

    A first chance exception of type ‘System.InvalidOperationException’ occurred in PresentationFramework.dll

    Additional information: A TwoWay or OneWayToSource binding cannot work on the read-only property ‘Date’ of type ‘<>f__AnonymousType1`8[System.String,System.Double,System.Double,System.Double,System.Double,System.Double,System.Double,System.Double]’.

    Any help would be greatly appreciated.

    Thanks,

    Jason

    Imported from legacy forums. Posted by Neo (had 576 views)

    Diane [Xceed]
    Moderator
    Post count: 1353

    Hi Jason,

    One possible explanation is that the GetFittedWidth will only return a valid value for columns that are currently visible in the Viewport, and the width will also be calculated on the values currently visible in the Viewport.

    Imported from legacy forums. Posted by Diane [Xceed] (had 3475 views)

    User (Old forums)
    Member
    Post count: 23064

    Yes, it seems this was the case!  I have resolved it by adding a call to UpdateLayout() at the end of every iteration of the foreach loop in AutoFit().  This doesn’t seem ideal as it’s causing lots of work/overhead, but this is unnoticeable to the user for the number of columns I’m using (less than 20).

    If there’s a more ideal solution, would love to know!

    Furthermore, I’ve noticed that GetFittedWidth() doesn’t take account of the width of the StatCell in my TableView.Footer.  But if I place the DataGridControl inside a StackPanel, it does take account of it!  Why is this?

    The StatCell is made up of two TextBlocks inside a horizontally-orientated StackPanel as follows:

      <xcdg:StatCell FieldName=”Nop”>
        <xcdg:StatCell.ContentTemplate>
          <DataTemplate>
            <StackPanel Orientation=”Horizontal” HorizontalAlignment=”Right”>
              <TextBlock Text=”{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=TotalNopText}” />
              <TextBlock Visibility=”{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=SumVisibility}” Text=”{Binding RelativeSource={RelativeSource Self}, Path=(xcdg:DataGridControl.StatContext).SumOfNop}”/>
            </StackPanel>
          </DataTemplate>
        </xcdg:StatCell.ContentTemplate>
      </xcdg:StatCell>

     

    TotalNopText is a property that simply returns “Netted Total:” and SumVisibility is a property that returns ‘true’.  SumOfNop is a SumFunction for the ‘Nop’ field.  I’ve noticed that if I undock the ContentPane containing the DataGridControl, the first TextBlock in the StatCell’s StackPanel above disappears!  Why is this too?

    Thanks for your help,

    Jason

    Imported from legacy forums. Posted by Neo (had 4036 views)

Viewing 15 posts - 1 through 15 (of 15 total)
  • You must be logged in to reply to this topic.