比较 List 和 Observable Collection 并从 Observable Collection 中移除差异
Compare List and Observable Collection and remove differences from Observable Collection
我正在尝试解决我正在处理的一些现有代码的问题,其中 ObservableCollection 是从列表构建的,但是当项目从第一个列表中删除时(当它从头开始重新生成时)它们不会被删除来自 ObservableCollection。该列表是作为 DLL 的一部分生成的,ObservableCollection 是 exe 文件的一部分,数据通过使用 delegate/event/invoke 在两者之间传递。该列表指向一个 class,其中包含一个索引,该索引可以唯一标识该 class 的每个实例。
代码如下所示:
DLL
public delegate void EntryListUpdateDelegate(string sender, CarInfo car);
public event EntryListUpdateDelegate OnEntrylistUpdate;
List<CarInfo> _entryListCars = new List<CarInfo>();
case InboundMessageTypes.ENTRY_LIST:
{
_entryListCars.Clear();
var carEntryCount = br.ReadUInt16();
for (int i = 0; i < carEntryCount; i++)
{
_entryListCars.Add(new CarInfo(br.ReadUInt16()));
}
}
case InboundMessageTypes.ENTRY_LIST_CAR:
{
var carId = br.ReadUInt16();
var carInfo = _entryListCars.SingleOrDefault(x => x.CarIndex == carId);
// ... Set attributes for car e.g. carInfo.TeamName = ReadString(br);
OnEntrylistUpdate?.Invoke(ConnectionIdentifier, carInfo);
}
上面的代码定期 运行 重新创建 entryList 并保持最新。
CarInfo 结构如下所示:
public class CarInfo
{
public ushort CarIndex { get; }
....
}
EXE
使用委托事件将数据从 DLL 传递到 EXE,ObservableCollection 在 ViewModel 中创建如下:
public ObservableCollection<CarViewModel> Cars { get; } = new ObservableCollection<CarViewModel>();
internal void RegisterNewClient(MyUdpRemoteClient newClient)
{
if (newClient.MsRealtimeUpdateInterval > 0)
{
// This client will send realtime updates, we should listen
newClient.MessageHandler.OnTrackDataUpdate += MessageHandler_OnTrackDataUpdate;
newClient.MessageHandler.OnEntrylistUpdate += MessageHandler_OnEntrylistUpdate;
newClient.MessageHandler.OnRealtimeUpdate += MessageHandler_OnRealtimeUpdate;
newClient.MessageHandler.OnRealtimeCarUpdate += MessageHandler_OnRealtimeCarUpdate;
}
_clients.Add(newClient.MessageHandler);
}
private void MessageHandler_OnEntrylistUpdate(string sender, CarInfo carUpdate)
{
CarViewModel vm = Cars.SingleOrDefault(x => x.CarIndex == carUpdate.CarIndex);
if (vm == null)
{
vm = new CarViewModel(carUpdate.CarIndex);
Cars.Add(vm);
}
vm.Update(carUpdate);
}
Cars 然后在 xaml 文件中用于在 CollectionViewSource 的 WPF GUI 的条目列表中显示汽车列表。
问题:
DLL 中的_entryListCars 总是更新和准确,因为它经常被清除和重新更新。出现的新车已成功添加到 Cars ObservableCollection,但 disconnect/die 不再属于 _entryListCars 的汽车永远不会从 Cars ObservableCollection 中删除。它只会越来越大,并继续显示 dead/inactive 辆汽车。
我的问题:
从 Cars ObservableCollection 中删除 dead/inactive 汽车的最佳方法是什么?我想知道我是否能够使用 Except (list1.Except(list2)) 比较这两个列表,然后使用 maybe Contains on 删除 Cars ObservableCollection 中不在 _entryListCars 列表中的所有汽车条目CarIndex 和 Cars.Remove/RemoveAt/RemoveItem?实现此目标的最佳方法是什么?代码会是什么样子?
感谢您的帮助。
看看你的事件处理程序 MessageHandler_OnEntrylistUpdate
命名会向我表明它需要一个列表作为事件参数,而不仅仅是一个新的 CarInfo
。因此,为了保留该命名,您可以 "fix" 的一种方法是更改事件以将整个列表作为输入传递:
public event EventHandler<List<CarInfo>> OnEntrylistUpdate;
// ...
OnEntrylistUpdate.Invoke(_entryListCars);
然后在你的事件处理程序中(你可以根据需要做的更聪明):
private void MessageHandler_OnEntrylistUpdate(string sender, List<CarInfo> updatedCarList)
{
var newCars = updatedCarList
.Where(uc => !Cars.Any(c => c.CarIndex == uc.CarIndex)
.Select(c => new CarViewModel(c.CarIndex))
.ToList();
var existingCars = Cars
.Where(c => updatedCarList.Any(uc => uc.CarIndex == c.CarIndex)
.ToList();
var removedCars = Cars
.Except(existingCars)
.ToList();
// Do whatever you need with your cars...
foreach (var car in newCars)
Cars.Add(car);
foreach (var car in removedCars)
Cars.Remove(car);
foreach (var car in newCars.Concat(existingCars))
car.Update(updatedCarList.Single(uc => uc.CarIndex == car.CarIndex));
}
综上所述,我建议您研究一下是否可以避免每次都更新整个列表,而是一次只更新 add/remove/update 一辆车。这当然需要你的来源支持。
我正在尝试解决我正在处理的一些现有代码的问题,其中 ObservableCollection 是从列表构建的,但是当项目从第一个列表中删除时(当它从头开始重新生成时)它们不会被删除来自 ObservableCollection。该列表是作为 DLL 的一部分生成的,ObservableCollection 是 exe 文件的一部分,数据通过使用 delegate/event/invoke 在两者之间传递。该列表指向一个 class,其中包含一个索引,该索引可以唯一标识该 class 的每个实例。
代码如下所示:
DLL
public delegate void EntryListUpdateDelegate(string sender, CarInfo car);
public event EntryListUpdateDelegate OnEntrylistUpdate;
List<CarInfo> _entryListCars = new List<CarInfo>();
case InboundMessageTypes.ENTRY_LIST:
{
_entryListCars.Clear();
var carEntryCount = br.ReadUInt16();
for (int i = 0; i < carEntryCount; i++)
{
_entryListCars.Add(new CarInfo(br.ReadUInt16()));
}
}
case InboundMessageTypes.ENTRY_LIST_CAR:
{
var carId = br.ReadUInt16();
var carInfo = _entryListCars.SingleOrDefault(x => x.CarIndex == carId);
// ... Set attributes for car e.g. carInfo.TeamName = ReadString(br);
OnEntrylistUpdate?.Invoke(ConnectionIdentifier, carInfo);
}
上面的代码定期 运行 重新创建 entryList 并保持最新。
CarInfo 结构如下所示:
public class CarInfo
{
public ushort CarIndex { get; }
....
}
EXE
使用委托事件将数据从 DLL 传递到 EXE,ObservableCollection 在 ViewModel 中创建如下:
public ObservableCollection<CarViewModel> Cars { get; } = new ObservableCollection<CarViewModel>();
internal void RegisterNewClient(MyUdpRemoteClient newClient)
{
if (newClient.MsRealtimeUpdateInterval > 0)
{
// This client will send realtime updates, we should listen
newClient.MessageHandler.OnTrackDataUpdate += MessageHandler_OnTrackDataUpdate;
newClient.MessageHandler.OnEntrylistUpdate += MessageHandler_OnEntrylistUpdate;
newClient.MessageHandler.OnRealtimeUpdate += MessageHandler_OnRealtimeUpdate;
newClient.MessageHandler.OnRealtimeCarUpdate += MessageHandler_OnRealtimeCarUpdate;
}
_clients.Add(newClient.MessageHandler);
}
private void MessageHandler_OnEntrylistUpdate(string sender, CarInfo carUpdate)
{
CarViewModel vm = Cars.SingleOrDefault(x => x.CarIndex == carUpdate.CarIndex);
if (vm == null)
{
vm = new CarViewModel(carUpdate.CarIndex);
Cars.Add(vm);
}
vm.Update(carUpdate);
}
Cars 然后在 xaml 文件中用于在 CollectionViewSource 的 WPF GUI 的条目列表中显示汽车列表。
问题:
DLL 中的_entryListCars 总是更新和准确,因为它经常被清除和重新更新。出现的新车已成功添加到 Cars ObservableCollection,但 disconnect/die 不再属于 _entryListCars 的汽车永远不会从 Cars ObservableCollection 中删除。它只会越来越大,并继续显示 dead/inactive 辆汽车。
我的问题:
从 Cars ObservableCollection 中删除 dead/inactive 汽车的最佳方法是什么?我想知道我是否能够使用 Except (list1.Except(list2)) 比较这两个列表,然后使用 maybe Contains on 删除 Cars ObservableCollection 中不在 _entryListCars 列表中的所有汽车条目CarIndex 和 Cars.Remove/RemoveAt/RemoveItem?实现此目标的最佳方法是什么?代码会是什么样子?
感谢您的帮助。
看看你的事件处理程序 MessageHandler_OnEntrylistUpdate
命名会向我表明它需要一个列表作为事件参数,而不仅仅是一个新的 CarInfo
。因此,为了保留该命名,您可以 "fix" 的一种方法是更改事件以将整个列表作为输入传递:
public event EventHandler<List<CarInfo>> OnEntrylistUpdate;
// ...
OnEntrylistUpdate.Invoke(_entryListCars);
然后在你的事件处理程序中(你可以根据需要做的更聪明):
private void MessageHandler_OnEntrylistUpdate(string sender, List<CarInfo> updatedCarList)
{
var newCars = updatedCarList
.Where(uc => !Cars.Any(c => c.CarIndex == uc.CarIndex)
.Select(c => new CarViewModel(c.CarIndex))
.ToList();
var existingCars = Cars
.Where(c => updatedCarList.Any(uc => uc.CarIndex == c.CarIndex)
.ToList();
var removedCars = Cars
.Except(existingCars)
.ToList();
// Do whatever you need with your cars...
foreach (var car in newCars)
Cars.Add(car);
foreach (var car in removedCars)
Cars.Remove(car);
foreach (var car in newCars.Concat(existingCars))
car.Update(updatedCarList.Single(uc => uc.CarIndex == car.CarIndex));
}
综上所述,我建议您研究一下是否可以避免每次都更新整个列表,而是一次只更新 add/remove/update 一辆车。这当然需要你的来源支持。