Xaml ViewModel触发器集合更改为跟踪ID值

Xaml ViewModel触发器集合更改为跟踪ID值,xaml,mvvm,windows-runtime,Xaml,Mvvm,Windows Runtime,我在一个新的WinRT应用程序中遇到了一个情况,我需要管理对象集合上的ID属性。本质上,我持有每个对象的唯一ID,我需要为添加的每个新对象增加该ID。这是因为我将序列化为XML以保存数据,因此需要自己管理此ID。如果我使用SQL,它将是一个自动递增的字段 我能想到的最好的方法是使用一个从构造函数调用的方法来设置它,然后让一个集合更改处理程序帮助我每次更新该值 以下是视图模型类: using MM.Models; using System.Collections.ObjectModel; usin

我在一个新的WinRT应用程序中遇到了一个情况,我需要管理对象集合上的ID属性。本质上,我持有每个对象的唯一ID,我需要为添加的每个新对象增加该ID。这是因为我将序列化为XML以保存数据,因此需要自己管理此ID。如果我使用SQL,它将是一个自动递增的字段

我能想到的最好的方法是使用一个从构造函数调用的方法来设置它,然后让一个集合更改处理程序帮助我每次更新该值

以下是视图模型类:

using MM.Models;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace MM.ViewModels
{
    public class VehiclesViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        public VehiclesViewModel()
        {
            Vehicles = new ObservableCollection<Vehicle>();
            NewVehicle = new Vehicle();
            NextVehicleID = CalculateHighestID(Vehicles.AsQueryable()) + 1;
            Vehicles.CollectionChanged += new NotifyCollectionChangedEventHandler(VehicleCollectionChanged);
        }

        private ObservableCollection<Vehicle> _vehicles;
        public ObservableCollection<Vehicle> Vehicles
        {
            get 
            { 
                return _vehicles; 
            }
            set
            {
                if (_vehicles != value)
                {
                    _vehicles = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Vehicles"));
                }
            }
        }

        void VehicleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                NextVehicleID += 1;
            }
        }

        public Vehicle NewVehicle { get; set; }

        private int _nextVehicleID;
        public int NextVehicleID 
        { 
            get 
            { 
                return _nextVehicleID; 
            }
            private set
            {
                _nextVehicleID = value;
                PropertyChanged(this, new PropertyChangedEventArgs("NextVehicleID"));
            }
        }

        private int CalculateHighestID(IQueryable<Vehicle> vehicles)
        {
            var query = vehicles.OrderByDescending(v => v.VehicleID).FirstOrDefault();
            if (query != null)
            {
                return query.VehicleID;
            }
            else
            {
                return 1;
            }
        }

    }
}
但是,从未调用VehicleCollectionChanged。作为一个测试,我使用相同的代码从构造函数方法中添加了一个车辆,这确实有效

有人能解释为什么不通过单击xaml按钮添加车辆来调用该方法吗


此外,是否有更好的总体方法来跟踪下一条记录的ID值?

在车辆类别中保留计数器如何

public class Vehicle
{
    static int NextId = 1;
    static object IdLock = new Object();

    public int VehicleId { get; set; }
    ...

    public Vehicle(int nextId = 0)
    {
         // can probably use interlocked increment instead
         // of keeping a separate lock object
         lock (IdLock)
         {
             if (nextId == 0)
             {
                 VehicleId = NextId++;
             }
             else
             {
                 NextId = nextId;
                 VehicleId = nextId;
             }
         }
    }
    ...
}

您可能希望根据保存的XML文件中的内容进行设置,而不是设置NextId=1。这样,它并不总是从1开始。

您的ID必须是
int
(或者是增量)?可能是GUID吗?至少您可以将创建留给
车辆
类。至于为什么不调用该事件,您是否在viewmodel上重新指定了“Vehicles”属性?是否有理由为该属性设置公共“集合”?您可以潜在地将新的ObservableCollection设置为“Vehicles”,而不是1)从旧事件中取下挂钩,2)将CollectionChanged事件连接到新集合。

我选择int有两个原因。第一种情况是,我后来在这个应用程序上安装了一个webapi后端,它很可能使用增量int作为数据库中的主键。我的第二个原因可能是对guid的非理性厌恶。我还在学习c#,所以不要真的听从你的建议。我假设我需要pubic set,因为我将从视图中添加到集合中。我假设通过从viewmodel添加一个项目,会引发changedevent。您将从viewmodel添加到集合中……您的视图将有一些“可见的方式”,让您的viewmodel知道它应该添加一个新项目(例如,与viewmodel上的命令绑定的按钮,其中command Execute方法向集合中添加了一个新项。您需要在Vehicles集合中设置的唯一原因是您计划从viewmodel外部分配一个新的ObservableCollection(听起来您不需要).但是,如果出于某种原因,您确实需要,您需要确保从集合中取消挂钩已更改的事件我尝试编辑我的评论,但时间不多了…我意识到您是从视图背后的代码添加的。这与模型视图模型“模式”不符您正在尝试跟随。我建议您阅读一下Commanding和MVVM的其余部分。我在最初的回答中得到的关于CollectionChanged事件为什么没有运行的意思是,您需要检查并查看是否正在将新的ObservableCollection分配给代码中其他任何地方的Vehicles属性……这意味着你订阅了唯一集合上的活动,但添加到了新集合中。我没有将此视为必须承认的事实。我不确定为什么在vehicle类中尝试此活动比在main view模型类中尝试更好。我不希望此类依赖于了解xml/内存集合中的其他项。我研究了一个更进一步,现在理解你的建议。我不知道静态变量是什么,但现在我知道了。我有这个工作,但不是ID的初始集,因为我不确定这样做的最佳方式。我可以在第一个对象的初始创建中传递一个变量吗?正如你所建议的,在创建第一个对象时传递ID是可能的上述代码已更改为允许此操作。
public class Vehicle
{
    static int NextId = 1;
    static object IdLock = new Object();

    public int VehicleId { get; set; }
    ...

    public Vehicle(int nextId = 0)
    {
         // can probably use interlocked increment instead
         // of keeping a separate lock object
         lock (IdLock)
         {
             if (nextId == 0)
             {
                 VehicleId = NextId++;
             }
             else
             {
                 NextId = nextId;
                 VehicleId = nextId;
             }
         }
    }
    ...
}