ListView
コントロールを使用して、いくつかのデータ行を表示しています。リストのコンテンツへの外部更新を受信するバックグラウンドタスクがあります。新しく受信したデータには、より少ない、より多い、または同じ数のアイテムが含まれている場合があり、アイテム自体が変更されている場合もあります。
ListView.ItemsSource
はOberservableCollection
(_itemList)にバインドされているので、_itemListへの変更はListView
でも表示されるはずです。
_itemList = new ObservableCollection<PmemCombItem>();
_itemList.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
L_PmemCombList.ItemsSource = _itemList;
ListView全体の更新を避けるために、新しく取得したリストと現在の_itemListを単純に比較し、同じではないアイテムを変更し、必要に応じてアイテムを追加/削除します。コレクション「newList」には新しく作成されたオブジェクトが含まれているため、_itemListのアイテムを置き換えると、「Refresh」通知が正しく送信されます(ObservableCollection`のイベントハンドラーOnCollectionChanged
を使用してログを記録できます)
Action action = () =>
{
for (int i = 0; i < newList.Count; i++)
{
// item exists in old list -> replace if changed
if (i < _itemList.Count)
{
if (!_itemList[i].SameDataAs(newList[i]))
_itemList[i] = newList[i];
}
// new list contains more items -> add items
else
_itemList.Add(newList[i]);
}
// new list contains less items -> remove items
for (int i = _itemList.Count - 1; i >= newList.Count; i--)
_itemList.RemoveAt(i);
};
Dispatcher.BeginInvoke(DispatcherPriority.Background, action);
私の問題は、このループで多くのアイテムが変更された場合、ListView
が更新されず、画面上のデータがそのままであるということです...これはわかりません。
このような単純なバージョンでも(すべての要素を交換)
List<PmemCombItem> newList = new List<PmemCombItem>();
foreach (PmemViewItem comb in combList)
newList.Add(new PmemCombItem(comb));
if (_itemList.Count == newList.Count)
for (int i = 0; i < newList.Count; i++)
_itemList[i] = newList[i];
else
{
_itemList.Clear();
foreach (PmemCombItem item in newList)
_itemList.Add(item);
}
正常に動作していません
これに関する手がかりはありますか?
[〜#〜] update [〜#〜]
すべての要素を更新した後に手動で次のコードを呼び出すと、すべてが正常に機能します
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
しかし、もちろん、これにより、UIは、私がまだ避けたいすべてを更新します。
これが機能するために私がしなければならなかったことです。
MyListView.ItemsSource = null;
MyListView.ItemsSource = MyDataSource;
変更後、次を使用してリストビューを更新できます。より簡単です
listView.Items.Refresh();
私はそれが古い質問であることを知っていますが、私はこの問題につまずいただけです。更新されたフィールドのみに対して、null割り当てトリックまたはリフレッシュを使用したくありませんでした。
だから、MSDNを見て、この記事を見つけました: https://docs.Microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?redirectedfrom=MSDN&view=netframework-4.7.2
要約すると、このインターフェイスを実装するためのアイテムが必要なだけで、このオブジェクトを監視できることを自動的に検出します。
public class MyItem : INotifyPropertyChanged
{
private string status;
public string Status
{
get => status;
set
{
OnPropertyChanged(nameof(Status));
status = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
そのため、誰かがStatus
を変更するたびにイベントが呼び出されます。そして、あなたの場合、リストビューはPropertyChanged
イベントにハンドラーを自動的に追加します。
これはあなたの場合の問題を実際に処理しません(追加/削除)。ただし、そのためには、BindingList<T>
https://docs.Microsoft.com/en-us/dotnet/api/system.componentmodel.bindinglist-1?view=netframework-4.7.2
同じパターンを使用すると、トリックを使用せずにリストビューが適切に更新されます。
私はそれを行う方法を見つけました。それは本当にそれほど素晴らしいことではありませんが、うまくいきます。
YourList.ItemsSource = null;
// Update the List containing your elements (lets call it x)
YourList.ItemsSource = x;
これでListView
が更新されます(私のUAPで機能します:))