WinForms ListView、リロード時にスクロール位置を記憶
-
06-07-2019 - |
質問
8列のユーザーデータを入力しているリストビューがあります。ユーザーには自動更新を有効にするオプションがあります。これにより、ListViewがクリアされ、データベースの最新データが再入力されます。
問題は、アイテムがクリアされて再入力されると、表示領域がリストの先頭に戻ることです。したがって、2000のアイテム1000を見ると、そのアイテムに戻るのは非常に不便です。
基本的に、私が求めているのは、現在のスクロール距離(xおよびy)を取得して復元する方法ですか?
解決
しばらく前と同じ問題が発生し、モデルとリストを比較するアルゴリズムを実装することになったため、変更された要素のみを追加/削除しました。このように、大きな変更がない場合、リストは先頭にジャンプしませんでした。そして、私が達成したかった主なものは効率でした(リストが点滅しないように)。
他のヒント
ただ、バグの多いListView.TopItemプロパティを必死に使用しようとする人に情報を提供したかっただけです。
- ListView.EndUpdateを呼び出した後にTopItemプロパティを設定する必要があります
- ListViewコントロールのアイテムは、Textプロパティを他の何かに設定する必要があります String.Empty以外の場合、またはプロパティは機能しません。
- ListView.TopItemを設定すると、null参照例外が断続的にスローされます。このコード行は常に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)
{ }
ListViewのTopItemIndexプロパティは探しているものですが、VS2010リリースで修正されるべき確認済みのバグがいくつかあります。
とにかく、この仕事をするための私の回避策はこれをすることです:
listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;
何らかの理由で直接設定しても更新されませんが、最後の項目に設定してから、必要な項目に確実に機能します。
ListView.TopItemプロパティを見てください。インデックスがあり、リスト内での位置を含める必要があります。新しいリストでそのインデックスを見つけ、TopItemをそのアイテムに設定すると、自動的にスクロールするはずです。
残念ながら、いくつかの相互運用機能を使用して、ListViewの正確な位置にスクロールする必要があります。 GetScrollInfo winapi関数を使用して、既存のスクロール位置と SendMessage でその位置までスクロールします。
スクロール位置を維持するための私のソリューション:
フォームレベル変数:
private static int scrollSpot = 0;
現在のスポットを保存するためのリストビューの更新(タイマー、ボタンなど):
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];
同じ問題が発生していました。 1/2秒ごとに設定するlistViewがあり、TopItemをインデックス&gt;のListItemに設定すると目に見えるアイテム、その後、リストはtopItemとバック2スポットの間をジャンプしました。
したがって、問題を修正するために、EndUpdateの呼び出し後にTopItermを設定します。
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];
テストでは、選択したアイテムを保存するためにintを使用しましたが、TopItemは必要ありませんでした。また、View.TileまたはView.LargeIconを使用している場合、TopItemは例外をスローします。
このコードはスクロールバーを移動しません:
listView1.BeginUpdate();
listView1.Items.Clear();
// loop through your add routine
listView1.Items.Add(lvi);
listView1.EndUpdate();