比较列表和可观察的集合,并从可观察的集合中删除差异

时间:2020-05-17 10:31:46

标签: c# wpf viewmodel

我正在尝试解决一些我正在使用List构建ObservableCollection的现有代码的问题,但是当从第一个列表中删除项目时(从头开始重新生成时),这些项目并未从中删除。 ObservableCollection。该列表作为DLL的一部分生成,而ObservableCollection在exe文件的一部分中,并且通过使用委托/事件/调用在两者之间传递数据。该列表指向一个包含索引的类,该索引可以唯一地标识该类的每个实例。

代码如下:

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,然后在ViewModel中创建ObservableCollection,如下所示:

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);
}

然后在xaml文件中使用汽车在CollectionViewSource的WPF GUI中的条目列表中显示汽车列表。

问题:

DLL中的

_entryListCars总是被更新且准确,因为它经常被清除并重新更新。随之而来的新车已成功添加到Cars ObservableCollection中,但是断开连接/死掉的车不再是_entryListCars的一部分,则永远不会从Cars ObservableCollection中删除。它只会越来越大,并继续显示失效/不活动的汽车。

我的问题:

从“汽车观察站”收藏中删除失效/不活动的汽车的最佳方法是什么?我想知道我是否能够使用Except(list1.Except(list2))比较两个列表,然后使用可能包含在CarIndex上的包含项删除所有在Cars ObservableCollection中存在的,不在_entryListCars列表中的汽车项。 Cars.Remove / RemoveAt / RemoveItem?实现此目标的最佳方法是什么?代码将是什么样?

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

看着您的事件处理程序MessageHandler_OnEntrylistUpdate,该命名将向我表明它期望列表作为事件参数,而不仅仅是一个新的CarInfo。因此,为了保持命名不变,您可以“修复”此问题的一种方法是更改​​事件以将整个列表作为输入传递:

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));
}

说了这么多,我建议您调查一下是否可以避免每次都更新整个列表,而是一次添加/删除/更新一辆汽车。这当然需要您的消息来源支持。

相关问题