none
Height must be non-negative. RRS feed

  • Question

  • I've got a particularly troublesome WPF window that keeps throwing this error during a refresh.

    System.ArgumentException: Height must be non-negative.
       at System.Windows.Rect.set_Height(Double value)
       at System.Windows.Controls.VirtualizingStackPanel.ExtendViewport(IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider, Boolean isHorizontal, Rect viewport, VirtualizationCacheLength cacheLength, VirtualizationCacheLengthUnit cacheUnit, Size stackPixelSizeInCacheBeforeViewport, Size stackLogicalSizeInCacheBeforeViewport, Size stackPixelSizeInCacheAfterViewport, Size stackLogicalSizeInCacheAfterViewport, Size stackPixelSize, Size stackLogicalSize, Int32& itemsInExtendedViewportCount)
       at System.Windows.Controls.VirtualizingStackPanel.IsExtendedViewportFull()
       at System.Windows.Controls.VirtualizingStackPanel.ShouldItemsChangeAffectLayoutCore(Boolean areItemChangesLocal, ItemsChangedEventArgs args)
       at System.Windows.Controls.VirtualizingPanel.OnItemsChangedInternal(Object sender, ItemsChangedEventArgs args)
       at System.Windows.Controls.Panel.OnItemsChanged(Object sender, ItemsChangedEventArgs args)
       at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index)
       at System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
       at System.Windows.WeakEventManager.ListenerList`1.DeliverEvent(Object sender, EventArgs e, Type managerType)
       at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args)
       at System.Collections.ObjectModel.ReadOnlyObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
       at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
       at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item)
       at MS.Internal.Data.CollectionViewGroupRoot.AddToSubgroup(Object item, LiveShapingItem lsi, CollectionViewGroupInternal group, Int32 level, Object name, Boolean loading)
       at MS.Internal.Data.CollectionViewGroupRoot.AddToSubgroups(Object item, LiveShapingItem lsi, CollectionViewGroupInternal group, Int32 level, Boolean loading)
       at System.Windows.Data.ListCollectionView.PrepareGroups()
       at System.Windows.Data.ListCollectionView.PrepareLocalArray()
       at System.Windows.Data.ListCollectionView.RefreshOverride()
       at System.Windows.Data.CollectionView.RefreshInternal()
       at TTSMain.wdLocations.Refresh()
       at TTSMainDataCore.TTSDataCore.Save(Boolean RowAdded)
       at TTSMain.wdLocations.Save(Boolean& rowAdded)
       at TTSMain.wdLocations.btnSave_Click(Object sender, RoutedEventArgs e) 

    My code leaves off at TTSMain.wdLocations.Refresh, the rest is behind the scenes code from Microsoft .Net Framework.

    Here is my Refresh routine:

        Private Sub Refresh() Handles dsTTS.CoreReloaded
            vsCities.View.Refresh()
            vsLocations.View.Refresh()
            vsContacts.View.Refresh()
            vsLocationStatus.View.Refresh()
            vsLocationTypes.View.Refresh()
            dgLocations.UpdateLayout()
            If currentLocationsID <> Nothing Then dgLocations.MoveToRowByID(currentLocationsID)
            dgLocations.RefreshGroupExpanders()
        End Sub

    Here is my custom datagrid's WPF style for grouping:

    <Style x:Key="StandardGroupItem" TargetType="{x:Type GroupItem}">
                <Setter Property="Margin" Value="0,0,0,0"/>
                <Setter Property="MinHeight" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander Name="part_Expander" Background="#87007000" BorderBrush="#C5003800" Foreground="Black" BorderThickness="1,1,1,1" Margin="3" Padding="1" MinHeight="0" >
                                <!--IsExpanded="{Binding Path=ExpandGroups, RelativeSource={RelativeSource AncestorType=TTSMain:ccMasterDataGrid}}"-->
                                <Expander.Header>
                                    <DockPanel>
                                        <TextBlock Style="{StaticResource StandardFont}" FontWeight="Bold" Text="{Binding Path=ItemCount}" Width="Auto"/>
                                        <TextBlock Style="{StaticResource StandardFont}" FontWeight="Bold" Text=" : " Width="Auto"/>
                                        <TextBlock Style="{StaticResource StandardFont}" FontWeight="Bold" Text="{Binding Path=Name}" Width="Auto"/>
                                    </DockPanel>
                                </Expander.Header>
                                <Expander.Content>
                                    <ItemsPresenter />
                                </Expander.Content>
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

    Here is my custom datagrid's code for grouping:

     Protected Overrides Sub OnInitialized(ByVal e As System.EventArgs)
            MyBase.OnInitialized(e)
            Name = "dgMaster"
            AutoGenerateColumns = False
            EnableRowVirtualization = True
            Style = CType(Application.Current.FindResource("StandardDataGrid"), Style)
            'set group style:
            Dim datagridRowsPresenter As New FrameworkElementFactory(GetType(Primitives.DataGridRowsPresenter))
            Dim itemsPanelTemplate As New ItemsPanelTemplate With {.VisualTree = datagridRowsPresenter}
            Dim gStyle As New GroupStyle() With {.Panel = itemsPanelTemplate}
            Me.GroupStyle.Add(gStyle)
            gStyle.ContainerStyle = TryCast(Application.Current.FindResource("StandardGroupItem"), Style)
    
            Me.ContextMenu = New ContextMenu
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            Me.ContextMenu.Items.Add(New MenuItem())
            miSearch = Me.ContextMenu.Items(0)
            miQuickFilter = Me.ContextMenu.Items(1)
            miUnFilter = Me.ContextMenu.Items(2)
            miUnsort = Me.ContextMenu.Items(3)
            miGroup = Me.ContextMenu.Items(4)
            miAddNew = Me.ContextMenu.Items(5)
            miCopyClip = Me.ContextMenu.Items(6)
            miDelete = Me.ContextMenu.Items(7)
            miSearch.Style = CType(Application.Current.FindResource("SearchMenuItem"), Style)
            miUnFilter.Style = CType(Application.Current.FindResource("UnFilterMenuItem"), Style)
            miGroup.Style = CType(Application.Current.FindResource("GroupByMenuItem"), Style)
            miQuickFilter.Style = CType(Application.Current.FindResource("QuickFilterMenuItem"), Style)
            miAddNew.Style = CType(Application.Current.FindResource("AddNewMenuItem"), Style)
            miCopyClip.Style = CType(Application.Current.FindResource("CopyClipMenuItem"), Style)
            miUnsort.Style = CType(Application.Current.FindResource("UnSortMenuItem"), Style)
            miDelete.Style = CType(Application.Current.FindResource("DeleteMenuItem"), Style)
            Me.CanUserDeleteRows = False
        End Sub
    
    
    #Region "Group"
    
        Public Overridable Sub GroupByFromMenuItem(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Try
                If Me.isSettingGroups Then Exit Sub
                CommitAllEdits()
                'group by that column
                If TypeOf sender Is MenuItem Then
                    Dim mi As MenuItem = sender
                    Dim strColumn As String = mi.Header
                    If strColumn <> String.Empty Then
                        'add/remove column to grouping
                        Select Case mi.IsChecked
                            Case True
                                'add column
                                For Each gCol As DataColumn In groupColumns
                                    If GetPureColumnHeader(gCol.Column.Header) = strColumn Then Exit Select
                                Next
                                For Each fCol As DataColumn In FilterColumns
                                    If GetPureColumnHeader(fCol.Column.Header) = strColumn Then
                                        groupColumns.Add(fCol)
                                    End If
                                Next
                            Case False
                                'remove column
                                For Each gCol As DataColumn In groupColumns
                                    If GetPureColumnHeader(gCol.Column.Header) = strColumn Then
                                        groupColumns.Remove(gCol)
                                        Exit For
                                    End If
                                Next
                        End Select
                        GroupRows()
                    End If
                End If
                BringCurrentIntoView()
                CreateGroupEvents()
            Catch ex As Exception
                Dim eh As New ErrorHandler(ex)
                eh.HandleIt()
            End Try
        End Sub
    
        Public Sub GroupByFromColumn(dgcObject As DataGridColumn)
            Try
                isSettingGroups = True
                CommitAllEdits()
                Dim gCol As DataColumn = groupColumns.Find(Function(x) x.Column Is dgcObject)
                If gCol Is Nothing Then 'not already in group columns
                    gCol = FilterColumns.Find(Function(x) x.Column Is dgcObject) 'find as a filter column (all columns should be here)
                    If gCol IsNot Nothing Then groupColumns.Add(gCol) 'add datacolumn to group columns list
                End If
                For Each miEx As MenuItem In miGroup.Items
                    If miEx.Header = gCol.Column.Header Then
                        miEx.IsChecked = True
                    End If
                Next
                GroupRows()
                BringCurrentIntoView()
                CreateGroupEvents()
                isSettingGroups = False
            Catch ex As Exception
                Dim eh As New ErrorHandler(ex)
                eh.HandleIt()
            End Try
        End Sub
    
        Public Overridable Function GetPureColumnHeader(ByVal strHeader As String) As String
            Dim splitSort() As String = strHeader.Split("(")
            strHeader = splitSort(0).TrimEnd(" ")
            Dim splitFilter() As String = strHeader.Split("{")
            strHeader = splitFilter(0).TrimEnd(" ")
            Return strHeader
        End Function
    
        Public Overridable Sub GroupRows()
            LCV.GroupDescriptions.Clear()
            sortComp.SortColumns.Clear()
            For Each gcol As DataColumn In groupColumns
                Dim rdvc As New RelationalDataValueComparer
                rdvc.ColumnFullName = gcol.ColumnFullName
                Dim gd As New PropertyGroupDescription(Nothing, rdvc)
                sortComp.SortColumns.Add(gcol)
                LCV.GroupDescriptions.Add(gd)
            Next
        End Sub
    
        Public Sub CreateGroupEvents()
            If LCV.Groups IsNot Nothing Then
                If LCV.Groups.Count > 0 Then
                    If groupItemsExpanders IsNot Nothing Then
                        ClearGroupEvents()
                    Else
                        groupItemsExpanders = New Dictionary(Of Object, Boolean)
                    End If
                    Dim sp As System.Windows.Controls.Primitives.DataGridRowsPresenter = FindChildUIElement(Me, GetType(DataGridRowsPresenter))
                    If sp IsNot Nothing Then
                        For Each gi As GroupItem In sp.Children
                            Dim exp As Expander = FindChildUIElement(gi, GetType(Expander))
                            groupItemsExpanders.Add(gi.DataContext.Name, exp.IsExpanded)
                        Next
                    End If
                Else
                    ClearGroupEvents()
                End If
            End If
        End Sub
    
        Public Sub ClearGroupEvents()
            groupItemsExpanders.Clear()
        End Sub
    
    
        Public Sub ExpandGroup(groupName As String, Optional setExpanded As Boolean = True)
            For Each grp As Object In LCV.Groups
                If grp.name = groupName Then
                    Dim sp As System.Windows.Controls.Primitives.DataGridRowsPresenter = FindChildUIElement(Me, GetType(DataGridRowsPresenter))
                    If sp IsNot Nothing Then
                        For Each gi As GroupItem In sp.Children
                            If gi.DataContext.Name = groupName Then
                                Dim exp As Expander = FindChildUIElement(gi, GetType(Expander))
                                exp.IsExpanded = setExpanded
                                Exit Sub
                            End If
                        Next
                    End If
                    Exit Sub
                End If
            Next
        End Sub
    
        Public Sub RefreshGroupExpanders()
            For Each kvp As KeyValuePair(Of Object, Boolean) In groupItemsExpanders
                ExpandGroup(kvp.Key, kvp.Value)
            Next
        End Sub
    
    #End Region
    

    Can someone identify any reason for the error that I can change to prevent its reoccurance?

    Thank you,

    Wednesday, May 23, 2018 4:03 PM

Answers

  • Hi Jamie,

    >>WPF window that keeps throwing this error during a refresh

    The most likely reason is that the CollectionViewSource refreshing/changing while the VirtualizingStackPanel is in the middle of Measure.

    We recommend you work around the problem. Please do the collection changes/refreshes in a dispatcher task via BeginInvoke, so that they don't happen during Measure. You can use a high priority to ensure that the changes show up in the UI by the time the next render occurs.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, May 24, 2018 6:22 AM
    Moderator

All replies

  • Hi Jamie,

    >>WPF window that keeps throwing this error during a refresh

    The most likely reason is that the CollectionViewSource refreshing/changing while the VirtualizingStackPanel is in the middle of Measure.

    We recommend you work around the problem. Please do the collection changes/refreshes in a dispatcher task via BeginInvoke, so that they don't happen during Measure. You can use a high priority to ensure that the changes show up in the UI by the time the next render occurs.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, May 24, 2018 6:22 AM
    Moderator
  • I tried this, and it appears to have shut up.

     Private Sub Refresh() Handles dsTTS.CoreReloaded
            Dispatcher.BeginInvoke(Sub() vsCities.View.Refresh(), Windows.Threading.DispatcherPriority.Send, Nothing)
            Dispatcher.BeginInvoke(Sub() vsLocations.View.Refresh(), Windows.Threading.DispatcherPriority.Send, Nothing)
            Dispatcher.BeginInvoke(Sub() vsContacts.View.Refresh(), Windows.Threading.DispatcherPriority.Send, Nothing)
            Dispatcher.BeginInvoke(Sub() vsLocationStatus.View.Refresh(), Windows.Threading.DispatcherPriority.Send, Nothing)
            Dispatcher.BeginInvoke(Sub() vsLocationTypes.View.Refresh(), Windows.Threading.DispatcherPriority.Send, Nothing)
            Dispatcher.BeginInvoke(Sub() dgLocations.UpdateLayout(), Windows.Threading.DispatcherPriority.Send, Nothing)
            If currentLocationsID <> Nothing Then
                Dispatcher.BeginInvoke(Sub() dgLocations.MoveToRowByID(currentLocationsID), Windows.Threading.DispatcherPriority.Send, Nothing)
            End If
            ' Dispatcher.BeginInvoke(Sub() dgLocations.RefreshGroupExpanders(), Windows.Threading.DispatcherPriority.Send, Nothing)
        End Sub


    jvj

    Thursday, June 7, 2018 3:58 PM