2010-01-07 33 views
10

Tôi có một bảng SQL có chứa 1 triệu hàng sẽ phát triển theo thời gian.Windows Forms DataGridView có thực hiện chế độ ảo thực sự không?

Có yêu cầu người dùng cụ thể để hiển thị lưới có thể sắp xếp hiển thị tất cả các hàng không có phân trang. Người dùng hy vọng có thể nhanh chóng nhảy từ hàng này sang hàng khác và từ trên xuống dưới bằng cách sử dụng thanh cuộn.

Tôi quen với lưới "chế độ ảo" chỉ hiển thị một tập hợp con có thể nhìn thấy của dữ liệu tổng thể. Họ có thể cung cấp hiệu suất UI tuyệt vời và yêu cầu bộ nhớ tối thiểu, (Tôi thậm chí đã thực hiện một ứng dụng bằng cách sử dụng kỹ thuật này nhiều năm trước đây).

Windows Forms DataGridView cung cấp chế độ ảo giống như là câu trả lời. Tuy nhiên không giống như các chế độ ảo khác mà tôi đã gặp phải, nó vẫn cấp phát bộ nhớ cho mỗi hàng (được xác nhận trong ProcessExplorer). Rõ ràng điều này gây ra việc sử dụng bộ nhớ tổng thể để tăng không cần thiết và, trong khi phân bổ các hàng này, có một sự chậm trễ đáng chú ý. Hiệu suất cuộn cũng chịu trên 1 triệu + hàng.

Chế độ ảo thực sẽ không cần phân bổ bộ nhớ cho các hàng không được hiển thị. Bạn chỉ cần cung cấp cho nó tổng số hàng (ví dụ: 1.000.000) và tất cả các lưới điện là quy mô thanh cuộn cho phù hợp. Khi nó lần đầu tiên được hiển thị lưới chỉ đơn giản là yêu cầu dữ liệu n đầu tiên (nói 30) chỉ hiển thị các hàng, hiển thị tức thì.

Khi người dùng cuộn lưới, chênh lệch hàng đơn giản và số hàng hiển thị được cung cấp và có thể được sử dụng để truy xuất dữ liệu từ kho dữ liệu.

Dưới đây là một ví dụ về mã DataGridView Tôi hiện đang sử dụng:

public void AddVirtualRows(int rowCount) 
{ 
    dataGridList.ColumnCount = 4; 


    dataGridList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; 
    dataGridList.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; 

    dataGridList.VirtualMode = true; 

    dataGridList.RowCount = rowCount; 

    dataGridList.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridList_CellValueNeeded); 


} 
void dataGridList_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
{ 
    e.Value = e.RowIndex; 
} 

Am tôi thiếu bất cứ điều gì ở đây, hoặc là chế độ "ảo" của DataGridView không thực sự ảo ở tất cả?

[Cập nhật]

Có vẻ như ListView cũ tốt thực hiện chính xác loại chế độ ảo mà tôi đang tìm kiếm. Nhưng tiếc là ListView không có khả năng định dạng ô của DataGridView, vì vậy tôi không thể sử dụng nó.

Đối với những người khác có thể, tôi đã thử nghiệm nó với một bốn cột ListView (trong chế độ chi tiết), VirtualMode = True và VirtualListSize = 100.000.000 hàng.

Danh sách được hiển thị ngay lập tức với 30 hàng đầu tiên hiển thị. Sau đó tôi có thể cuộn nhanh đến cuối danh sách mà không bị chậm trễ. Việc sử dụng bộ nhớ là không đổi 10 MB mọi lúc.

Trả lời

1

Câu trả lời là KHÔNG

see first comment here

nếu có ai biết một cách tốt hơn, hãy cho chúng tôi biết

+0

Tôi nghĩ rằng liên kết trỏ đến phiên bản recenet nhiều nhất và nhận xét không hiển thị ở đó. Đây có phải là commetn bắt đầu "Ví dụ này dường như không hoạt động khi sử dụng .NET 4.0" không? –

+0

tôi không biết nữa nhưng tôi đoán nó là ".NET Framework 3.0" không có gì "Visual Studio 2010" cũng thú vị – Firo

17

Chúng tôi chỉ có một yêu cầu tương tự để có thể hiển thị các bảng hàng 1M + tùy ý, không lập chỉ mục trong ứng dụng của chúng tôi với hiệu suất "rất tốt", sử dụng chứng khoán DataGridView. Lúc đầu, tôi nghĩ rằng nó là không thể, nhưng với đủ đầu gãi, chúng tôi đã đưa ra một cái gì đó hoạt động rất tốt sau khi chi tiêu ngày đổ qua Reflector và. NET Profiler. Điều này khó thực hiện, nhưng kết quả cũng đáng giá.

Cách chúng tôi giải quyết vấn đề này là bằng cách tạo ra một lớp mà thực hiện ITypedListIBindingList (bạn có thể gọi nó là LargeTableView, ví dụ) để quản lý việc thu hồi không đồng bộ và bộ nhớ đệm thông tin từ cơ sở dữ liệu. Chúng tôi cũng đã tạo một lớp kế thừa thuộc tính PropertyDescriptor (ví dụ: LargeTableColumnDescriptor) để truy xuất dữ liệu từ mỗi cột.

Khi bất động sản DataGridView.DataSource được đặt thành một lớp thực hiện IBindingList, nó đi vào một chế độ giả ảo khác với VirtualMode thường xuyên, nơi như khi mỗi hàng được sơn (chẳng hạn như khi người dùng cuộn), DataGridView truy cập vào chỉ mục [] trên IBindingList và các phương pháp tương ứng GetValue trên mỗi cột của PropertyDescriptor để truy xuất các giá trị nếu cần. Sự kiện CellValueNeeded không được nâng lên. Trong trường hợp của chúng tôi, chúng tôi truy cập vào cơ sở dữ liệu khi người lập chỉ mục được truy cập, và sau đó lưu vào bộ nhớ cache giá trị, để các lần tái sơn tiếp theo không nhấn vào cơ sở dữ liệu.

Tôi đã thực hiện lại các thử nghiệm tương tự: sử dụng bộ nhớ. Các DataGridView không phân bổ một mảng đó là kích thước của danh sách (tức là 1M hàng), tuy nhiên mỗi mục trong mảng ban đầu tham chiếu một DataGridViewRow duy nhất, do đó sử dụng bộ nhớ là chấp nhận được. Tôi không chắc chắn nếu hành vi là như nhau khi VirtualMode là đúng sự thật. Chúng tôi có thể loại bỏ độ trễ cuộn bằng cách trả lại ngay String.Empty trong phương thức GetValue nếu hàng không được lưu trong bộ nhớ cache và sau đó thực hiện truy vấn cơ sở dữ liệu một cách không đồng bộ. Khi yêu cầu không đồng bộ được hoàn tất, bạn có thể nâng cao sự kiện IBindingList.ListChanged để báo hiệu cho DataGridView rằng nó sẽ vẽ lại các ô, ngoại trừ thời gian này đọc từ bộ nhớ cache sẵn có. Bằng cách đó, giao diện người dùng không bao giờ bị chặn chờ cuộc gọi cơ sở dữ liệu. Một điều chúng tôi nhận thấy là hiệu suất là tốt hơn đáng kể nếu bạn đặt DataSource hoặc số hàng ảo trước khi thêm DataGridView vào biểu mẫu - nó cắt thời gian khởi tạo làm đôi. Ngoài ra, hãy đảm bảo rằng bạn đã đặt cả Tự động đặt hàng và Cột thành None hoặc nếu không bạn sẽ gặp phải sự cố về hiệu suất bổ sung.

Lưu ý bên cạnh: cách chúng tôi thực hiện "tải" bảng lớn như vậy trong ứng dụng .NET của chúng tôi là tạo bảng tạm thời trên máy chủ SQL liệt kê các khóa chính theo thứ tự sắp xếp mong muốn cùng với một IDENTITY (hàng) số) và sau đó duy trì kết nối cho các yêu cầu hàng tiếp theo. Điều này tự nhiên cần có thời gian để khởi tạo (xấp xỉ.3-5s trên một máy chủ SQL nhanh hợp lý), nhưng không có kiến ​​thức về các chỉ mục có sẵn, chúng tôi không có lựa chọn nào tốt hơn. Sau đó, trong triển khai ITypedList của chúng tôi, chúng tôi yêu cầu các hàng trong các trang của 100 hàng, trong đó hàng thứ 50 là hàng đang được vẽ, để chúng tôi giới hạn số lượng truy vấn được thực hiện mỗi lần người lập chỉ mục truy cập và có tất cả dữ liệu có sẵn trong ứng dụng của chúng tôi.

Đọc thêm:

http://msdn.microsoft.com/en-us/library/ms404298.aspx

http://msdn.microsoft.com/en-us/library/system.componentmodel.ibindinglist.aspx

+0

tôi đã cố gắng tái tạo việc thực hiện bạn mô tả, nhưng tôi nhấn một số vấn đề. 1) khi tôi đặt grid.DataSource vào danh sách liên kết của tôi, nó yêu cầu đếm và tất cả các thực thể ngay lập tức 2) tôi không thể quản lý cuộc gọi đến chỉ mục trong khi dữ liệu vẫn đang tìm nạp 3) làm mất hiệu lực bộ đệm khi sắp xếp thứ tự được thay đổi. trả lại kết quả cũ – Firo

+0

Thử trả lại số lượng là 0 nếu bạn chưa hoàn tất tìm nạp nền. Nếu bạn muốn gửi cho tôi một số mã của bạn, tôi sẽ rất vui khi có một cái nhìn. –

+0

thx cho ưu đãi. Làm thế nào tôi có thể gửi cho bạn mã? – Firo

0

tôi sẽ nói có ... miễn là bạn dính vào các sự kiện kích hoạt bởi các hành vi ảo Mode (ví dụ CellValueNeeded) và bạn chăm sóc tốt của thanh toán bù trừ tay xây dựng bộ đệm của bạn. Tôi đã hiển thị số lượng lớn dữ liệu, nhiều hơn 1 triệu mà không phiền phức.

Tôi có chút tò mò về việc triển khai Kevin McCormick bằng cách sử dụng DataSource dựa trên ITypedList hoặc bất kỳ triển khai giao diện liên quan đến IList nào. Tôi đoán nó chỉ là một lớp trừu tượng khác làm cho việc sử dụng bộ đệm trong và ngoài để cho phép người dùng hoặc nhà phát triển cấp quyền cho DataGridView với điều này, nhưng vẫn xử lý nội bộ với VirtualMode gốc để hiển thị thông tin bạn đã tải trong đệm.

Bên cạnh cách thời trang để giải quyết chế độ ảo, với tôi, vấn đề khó khăn duy nhất còn lại với DataGridView là giới hạn RowCount: nó vẫn là Int32.Max. Nó có lẽ là do di sản của hệ thống vẽ Winforms ... giống như hình ảnh hoặc thậm chí mọi thành viên kích thước, chiều rộng, chiều cao của điều khiển Winform ... tại sao không dính vào một loại UInt32?

Tôi giả định rằng không ai nhìn thấy Điều khiển hoặc hình ảnh có thứ nguyên phủ định, nhưng vẫn là loại không phù hợp với ngữ cảnh sử dụng.

Xem câu trả lời của tôi ở bên dưới, có thể giúp bạn nếu bạn vẫn gặp khó khăn, sự kiện nếu, tôi đoán nó đã được giải quyết cho các lứa tuổi bây giờ. https://stackoverflow.com/a/16373108/1906567

Các vấn đề liên quan