Windows Phone 8.1 ListView.ReorderMode不通知ObservableCollection

时间:2014-07-15 14:16:49

标签: c# listview windows-phone-8.1

在Windows Phone 8.1应用程序中(以Runtime而非Silverlight为目标),我有一个ObservableCollection绑定到ListView,定义如下:

<ListView ItemsSource="{Binding ListItems, Mode=TwoWay}" CanReorderItems="True" ReorderMode="Enabled">
    <ListView.ItemTemplate>
        ...etc...

在ViewModel的构造函数中,我也有

ListItems.CollectionChanged += ListItems_CollectionChanged;

这是在添加和删除任何项目时引发事件 - 但是,这些都是从VM而不是View处理的。不幸的是,当项目重新排序时,不会引发该事件。我已经设置了这个,移动了一些项目,在事件处理程序中添加了一个断点并添加了一个项目,我可以看到底层的ObservableCollection的顺序已经从View控制中发生了变化。那么为什么不举办活动呢?如果它不胜,那么在数据库中持久保存ListView订单的最佳做法是什么?

更新

这个问题实际上比我想象的要大......似乎ListView.CollectionChanged事件在添加项目时也没有触发!它在应用程序启动时执行,并从数据库加载,但不是由用户从UI添加。这很奇怪,因为使用完全相同的方法执行项目的添加。来自数据库:

private ViewModel MapFromModel(Item model, SQLiteAsyncConnection connection)
    {
        var viewModel = new ViewModel
        {
            Id = model.Id,
            Text = model.Text,
            Description = model.Description,
            Added = model.Added,
            Completed = model.Completed,
            DueOn = model.DueOn,
            ParentId = model.ParentId,
            DisplayOrderNumber = model.DisplayOrderNumber,
            IsNew = false
        };

        foreach (
            var childViewModel in
                connection.Table<Item>()
                    .Where(ci => ci.ParentId == viewModel.Id)
                    .ToListAsync()
                    .Result.Select(childItem => MapFromModel(childItem, connection)))
        {
            if (!_cache.Contains(childViewModel))
                _cache.Add(childViewModel);
            viewModel.AddItem(childViewModel);
        }
        return viewModel;
    }

您会看到此递归方法调用ViewModel的AddItem()方法来添加子项(具有相同类型)。我还有一个ICommand绑定到一个按钮来添加其他项目:

    public void Execute(object parameter)
    {
        var viewModel = parameter as ViewModel;
        if (viewModel == null) return;

        AddItem(viewModel);
    }
public static void AddItem(ViewModel viewModel)
    {
        // The DisplayOrderNumber of the new item needs to be the max of the current collection + 1.
        var displayOrderNumber = viewModel.ListItems.Any()
            ? viewModel.ListItems.Max(ci => ci.DisplayOrderNumber) + 1
            : 0;
        var newText = string.Format("{0} {1}",
            viewModel.Id == Guid.Empty ? "List" : "Item", displayOrderNumber + 1);
        var newItem = new ViewModel
        {
            Text = newText,
            NewText = newText,
            ParentId = viewModel.Id,
            InEditMode = true,
            Added = DateTime.Now,
            DisplayOrderNumber = displayOrderNumber,
            IsNew = true
        };
        viewModel.AddItem(newItem);
        viewModel.Save();
    }

那么为什么AddItem()方法在从服务层调用而不是从ViewModel层本身调用时会引发事件?

1 个答案:

答案 0 :(得分:1)

事实证明,像往常一样,错误完全是我的。

发生这种情况是因为事件处理方法ListItems_CollectionChanged正在断开连接。造成这种情况的原因是由于Sort方法正在替换底层连接。我已经解决了这个问题,如果需要,可以在属性的setter中添加事件处理程序(当然还要删除任何未使用的事件处理程序)。