WinForms ListView، تذكر الموقع الذي تم تمريره عند إعادة التحميل

StackOverflow https://stackoverflow.com/questions/626315

سؤال

لدي عرض قائمة أقوم بملئه بـ 8 أعمدة من بيانات المستخدم.لدى المستخدم خيار تمكين التحديث التلقائي، مما يؤدي إلى مسح ListView وإعادة ملؤه بأحدث البيانات من قاعدة البيانات.

تكمن المشكلة في أنه عند مسح العناصر وإعادة ملؤها، تعود المنطقة المرئية إلى أعلى القائمة.لذا، إذا كنت أنظر إلى البند رقم 1000 من عام 2000، فمن غير المناسب العودة إلى هذا العنصر.

في الأساس، ما أطرحه هو، كيف يمكنني الحصول على مسافات التمرير الحالية (x وy) ثم استعادتها؟

هل كانت مفيدة؟

المحلول

وكان لي نفس المشكلة مع فترة من الوقت قبل وانتهى بي الأمر تنفيذ خوارزمية لمقارنة هذا النموذج مع القائمة، لذلك أنا فقط إضافة / العناصر المحذوفة التي قد تغيرت. بهذه الطريقة إذا لم تكن هناك تغييرات هائلة في القائمة لم تقفز إلى البداية. وكان الشيء الرئيسي الذي يريد ان يحقق الكفاءة (حتى أن القائمة لا وميض).

نصائح أخرى

أردت فقط تقديم بعض المعلومات لأولئك الذين يحاولون بشدة استخدام خاصية ListView.TopItem التي تجرها الدواب:

  1. يجب عليك تعيين الخاصية TopItem بعد استدعاء ListView.EndUpdate
  2. يجب أن تحتوي عناصر التحكم في ListView على تعيين خاصية النص الخاصة بهم على شيء آخر غير String.Empty ، أو أن الخاصية لن تعمل.
  3. يؤدي تعيين ListView.TopItem إلى طرح استثناءات مرجعية فارغة بشكل متقطع.احتفظ دائمًا بهذا السطر من التعليمات البرمجية داخل كتلة Try...Catch.

بالطبع، سيؤدي هذا إلى انتقال شريط التمرير الخاص بـ ListView إلى 0 والعودة إلى موقع العنصر العلوي، وهو أمر مزعج.الرجاء تحديث هذا السؤال إذا وجدت حلاً بديلاً لهذه المشكلة.

ولقد استخدمت بنجاح التالية:

int topItemIndex = 0;
try
{
     topItemIndex = listView1.TopItem.Index;
}
catch (Exception ex)
{ }
listView1.BeginUpdate();
listView1.Items.Clear();
//CODE TO FILL LISTVIEW GOES HERE
listView1.EndUpdate();
try 
{ 
    listView1.TopItem = listView1.Items[topItemIndex];
}
catch (Exception ex)
{ }

والخاصية TopItemIndex على ListView هو ما كنت أبحث عنه، ومع ذلك فقد أكد بعض الأخطاء التي ينبغي أن تعالج في الإفراج VS2010 .. لست متأكدا (لم محددة).

وعلى أي حال، يا الحل لجعل هذا العمل هو أن تفعل هذا:

listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;

لسبب ما وضع مباشرة لا يحدث ذلك، ولكن تعيين إلى العنصر الأخير ثم واحد أريد أعمال موثوق بالنسبة لي.

ونظرة على الممتلكات ListView.TopItem. أنه يحتوي على المؤشر الذي يجب أن يحتوي على موقفها في القائمة. نجد أن المؤشر في القائمة الجديدة، ووضع TopItem لهذا البند، وأنه ينبغي أن تفعل التمرير تلقائيا.

ولسوء الحظ سوف تحتاج إلى استخدام بعض إمكانية التشغيل المتداخل للانتقال إلى الموضع الدقيق في ListView. استخدام GetScrollInfo WINAPI وظيفة للحصول على موقف التمرير القائمة و<أ href ل = "http://www.pinvoke.net/default.aspx/user32/SendMessage.html" يختلط = "نوفولو noreferrer"> SendMessage للانتقال إلى هذا المنصب.

وهناك في مقال على CodeProject اسمه التمرير إلى مجموعة مع ListView قد يرشدك إلى الحل.

وبلدي حل للحفاظ على موقف التمرير:

ومتغير مستوى نموذج:

private static int scrollSpot = 0;

وداخل تحديث listview (أي الموقت، زر) لتخزين بقعة الحالية:

scrollSpot = this.listView1.TopItem.Index;
refreshTheForm();

وداخل طريقة refreshTheForm لإظهار بقعة المخزنة (وضع في نهاية جدا من طريقة):

if (scrollSpot <= 1)
{
     listView1.Items[scrollSpot].Selected = true;
}
else
{
     listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0]; 

وكنت أعاني من نوع من نفس المشكلة. لدي listView أنني ملء كل 1/2 ثانية، وعندما وتعيين TopItem إلى عنصر القائمة التي مؤشر> العناصر المرئية، ثم القائمة قفزت بين topItem والعودة 2 البقع.

وهكذا، لتصحيح المشكلة، أنا وضعت TopIterm بعد استدعاء EndUpdate.

lvB.EndUpdate();
lvI.EndUpdate();
lvR.EndUpdate();

if (lstEntryInts.Items.Count > 0)
    lstEntryInts.TopItem = lstEntryInts.Items[iTopVisIdx];
if (lstEntryBools.Items.Count > 0)
    lstEntryBools.TopItem = lstEntryBools.Items[iTopVisIdx];
if (lstEntryReals.Items.Count > 0)
    lstEntryReals.TopItem = lstEntryReals.Items[iTopVisIdx];​

في بلدي التجارب، أنت لم تحتاج حتى للTopItem، على الرغم من أنني استخدم الباحث لحفظ العنصر المحدد. أيضا TopItem يطرح استثناء إذا كنت تستخدم View.Tile أو View.LargeIcon.

وهذا الرمز لا يتحرك أشرطة التمرير:

listView1.BeginUpdate();
listView1.Items.Clear();

// loop through your add routine
listView1.Items.Add(lvi);

listView1.EndUpdate();
scroll top