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