将自定义类绑定到WPF DataGrid时发生奇怪项目调用 [英] Strange Item calls when binding a custom class to WPF DataGrid

查看:84
本文介绍了将自定义类绑定到WPF DataGrid时发生奇怪项目调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好

我正在构建一个要绑定到WPF DataGrid的自定义数据类,并且遇到了一些麻烦.从它的外观看,似乎数据网格正在每隔一个其他请求就从我的自定义类中请求Item(0).因此,要显示数据,它会要求项目0,0,0,1,0,2,0,3,0,4,0,5 ...等.这应该是这种方式吗?

过程这让我感到悲痛,因为我的班级正在分页大量数据,并且请求项目1000000然后是0并返回到1000001会触发很多分页.我想我可以通过始终将Item 0保留在内存中来绕过此操作,但是仍然很高兴了解发生了什么...

关于它如何工作的任何评论?

我将在VB中包含一个简单的示例来说明问题.在Item()方法上添加一个断点,并观察传入的参数.

附带说明,在哪里可以找到有关如何使这些文章中的代码可表示的指南?



带有DataGrid的窗口的XAML:

Hello

I am building a custom data class which I want to bind to a WPF DataGrid, and I am experiencing some headaches. From the looks of it, it appears that the datagrid is asking for Item(0) from my custom class on every other request. So to present the data, it asks for Items 0,0,0,1,0,2,0,3,0,4,0,5 ... etc. Is this supposed to be this way?

The process It is giving me grief as my class is paging large amounts of data, and requesting item 1000000 and then 0 and back to 1000001 triggers a lot of paging. I suppose I can bypass this by always keeping Item 0 in memory, but it would nevertheless be nice to understand what is going on...

Any comments on how this works?

I''ll include a simple example in VB to illustrate the problem. Add a breakpoint at the Item() method, and watch the incoming argument.

On a side note, where can I find a guide on how to make code representable in these posts?



XAML for the Window with the DataGrid:

<window x:class="Viewer" xmlns:x="#unknown">
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Title="Window1" Height="300" Width="300">
 <grid>
        <datagrid autogeneratecolumns="True" name="DataGrid1" />
 </grid>
</window>





代码:(如果需要,将其全部放在MainWindow中)






Code: (Place it all in the MainWindow if you will)


Class MainWindow
      Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
            DoStuff()
      End Sub
      Public Sub DoStuff()
            'Create a viewable collection
            Dim coll As New ViewableCollection
            For i = 0 To 100
                  coll.Add(New PropClass("name" & i.ToString, i))
            Next

            'Bind to Viewer
            Dim view As New Viewer
            view.DataGrid1.ItemsSource = coll
            view.Show()
      End Sub
End Class
Public Class PropClass
      Public Name As String
      Public Value As Double
      Public Sub New(ByVal instanceName As String, ByVal instanceValue As Double)
            Name = instanceName
            Value = instanceValue
      End Sub
End Class





Public Class ViewableCollection
    Implements IList

    Private dataContainer As New List(Of PropClass)

    Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo

    End Sub

    Public ReadOnly Property Count As Integer Implements System.Collections.ICollection.Count
        Get
            Return dataContainer.Count
        End Get
    End Property

    Public ReadOnly Property IsSynchronized As Boolean Implements System.Collections.ICollection.IsSynchronized
        Get
            Return False
        End Get
    End Property

    Public ReadOnly Property SyncRoot As Object Implements System.Collections.ICollection.SyncRoot
        Get
            Return Nothing
        End Get
    End Property

    Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return New VCEnumerator(Me)
    End Function

    Public Function Add(ByVal value As Object) As Integer Implements System.Collections.IList.Add
        dataContainer.Add(CType(value, PropClass))
        Return dataContainer.Count - 1
    End Function

    Public Sub Clear() Implements System.Collections.IList.Clear
        dataContainer.Clear()
    End Sub

    Public Function Contains(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains
        Return dataContainer.Contains(DirectCast(value, PropClass))
    End Function

    Public Function IndexOf(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf
        Dim test = dataContainer.IndexOf(DirectCast(value, PropClass))
        Return dataContainer.IndexOf(DirectCast(value, PropClass))
    End Function

    Public Sub Insert(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert
        dataContainer.Insert(index, DirectCast(value, PropClass))
    End Sub

    Public ReadOnly Property IsFixedSize As Boolean Implements System.Collections.IList.IsFixedSize
        Get
            Return False
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements System.Collections.IList.IsReadOnly
        Get
            Return False
        End Get
    End Property

    Default Public Property Item(ByVal index As Integer) As Object Implements System.Collections.IList.Item
        Get
            Return dataContainer.Item(index)
        End Get
        Set(ByVal value As Object)
            dataContainer.Item(index) = DirectCast(value, PropClass)
        End Set
    End Property

    Public Sub Remove(ByVal value As Object) Implements System.Collections.IList.Remove
        dataContainer.Remove(DirectCast(value, PropClass))
    End Sub

    Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.IList.RemoveAt
        dataContainer.RemoveAt(index)
    End Sub

    Public Class VCEnumerator
        Implements IEnumerator
        Private _owner As ViewableCollection
        Private pointer As Integer = -1
        Private lastIdx As Integer

        Public ReadOnly Property Current As Object Implements System.Collections.IEnumerator.Current
            Get
                Return _owner.Item(pointer)
            End Get
        End Property

        Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
            pointer += 1
            Return pointer <= lastIdx
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            pointer = -1
        End Sub

        Public Sub New(ByVal owner As ViewableCollection)
            _owner = owner
            lastIdx = _owner.Count - 1
        End Sub
    End Class

End Class

推荐答案


我不知道这个问题对您是否仍然很重要.但是,我正在为DataGrid编写数据虚拟化解决方案,以允许用户无需分页就可以管理数百万行.我开发了一个列表类来完成繁重的工作,并开发了ItemsControl使用的CollectionView类.我也遇到了来自DataGrid的奇怪项目请求.

我隐瞒了一些事实:

1. CollectionView应使用IList(非通用),否则ItemsControl会将其视为IEnumerable,并查询/枚举所有行.这显然不是一个选择,因为重点是仅将那些由用户实际研究的页面保留在内存中.所以我实现了IList.

2.索引为0的行经常被DataGrid询问,这是因为该行用于可视项测量(根据调用堆栈).所以,我只是缓存这个.

3. DataGrid内部的缓存机制使用可预测的模式来查询其显示的行.首先,它要求从上到下的可见行(每行两次),然后在可见区域(包括第一可见行)之前以降序查询几行(取决于可见区域的大小),因此,从下到上.之后,它要求从顶部到底部的可见行(包括最后一个可见行)之后的行数相同.

我想知道为什么它要求不可见的行传送时间,因为这些行在可见时将再次被请求.我猜再次是测量原因.
如果页面大小设置正确,则可以满足当前和先前加载页面中的所有这些请求.

4.如果启用了CanSelectMultipleItems(正确),则使用SHIFT按钮选择多个项目时,DataGrid会使用IEnumerable接口枚举从列表的开头(!!!!)到选择结束的所有行.我真的不明白为什么...

我不得不关闭它,因为无法避免使用GetEnumerator方法.

5.如果所选行不可见,并且当前可视区域离所选行很远,则有时它会开始查询从所选行到可视区域末尾的所有项目.包括所有甚至不可见的行.

我无法弄清楚这种行为的确切模式.也许是我的实现导致了它.

我希望这些可以帮助某人.
Hi,
I don''t know whether this problem is still important for you. However, I am writing a data virtualization solution for DataGrid in order to allow the user to manage millions of rows without paging. I developed a list class which does the heavy work and a CollectionView class used by the ItemsControl. I am also experiencing weird item requests from the DataGrid.

I aprehended some facts:

1. The CollectionView should impelement IList (non generic) otherwise the ItemsControl will treat it as an IEnumerable and query/enumerate all the rows. Which is obviously not an option, since the point would be to keep only those pages in memory which are actually studied by the user. So I implemented IList.

2. The row with 0 index is frequently asked by the DataGrid, due to the fact that it is used for visual item measurement (according to the call stack). So, I simply cache this one.

3. The caching mechanism inside the DataGrid uses a predictable pattern to query the rows it shows. First it asks for the visible rows from top to bottom (twice every row), then it queries a couple of rows (depending on the size of the visible area) before the visible area (including the first visible row) in a descending order so, from bottom to top. After that it requests for a same amount of rows after the visible rows (inclucing the last visible row) from top to bottom.

I was wondering, why it requests for non visible rows evey time since those rows will be requested again when become visible. Measurement reasons again I guess.

If my page size is well set, I can serve all these requests from the current and previously loaded page.

4. If CanSelectMultipleItems is enabled (True), when selecting multiple items using the SHIFT button, the DataGrid enumerates all the rows from the begining(!!!!) of the list to the end of the selection using the IEnumerable interface. I really do not understand why...

I had to turn it off since I could not avoid the usage of GetEnumerator method.

5. If the selected row is not visible and the current visible area is far from the selected row, sometimes it starts querying all the items from the selected row to the end of the visible area. Including all the rows between which are not even visible.

I could not figure out the exact pattern of this behavior. Maybe my implementation causes it.

I hope these can help someone.


这篇关于将自定义类绑定到WPF DataGrid时发生奇怪项目调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆