MVVMCross(Droid)GridView在没有焦点的情况下不会更新?

时间:2014-03-06 20:02:39

标签: android xamarin.android xamarin mvvmcross

我对MVVMCross& amp; Xamarin,所以我很可能错过了一些简单的东西,但我有一个Mvx.MvxGridView布局绑定到一个简单的对象列表。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Mvx.MvxGridView
        android:numColumns="5"
        android:verticalSpacing="15dp"
        android:horizontalSpacing="15dp"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        local:MvxBind="ItemsSource Bikes"
        local:MvxItemTemplate="@layout/bikeassignmentview_bikeelement" />
</LinearLayout>

视图非常简单:

namespace Keiser.MPM.Screen.Droid.Views
{
    using Android.App;

    [Activity(Theme = "@style/Theme.FullScreen")]
    public class BikeAssignmentView : BaseView
    {
        protected override void OnCreate(Android.OS.Bundle bundle)
        {
            base.OnCreate(bundle);
            this.SetContentView(Resource.Layout.BikeAssignmentView_Page);
        }
    }
}

与视图模型相同:

namespace Keiser.MPM.Screen.Core.ViewModels
{
    using System.Collections.Generic;
    using System.Windows.Input;
    using Cirrious.CrossCore;
    using Cirrious.MvvmCross.ViewModels;
    using Keiser.MPM.Screen.Core.Models.Bikes;

    public class BikeAssignmentViewModel : BaseViewModel
    {
        private IBikeManagerService _bikeManagerService;
        private List<Bike> _bikes;
        public List<Bike> Bikes { get { return _bikes; } }

        public BikeAssignmentViewModel(IBikeManagerService bikeManagerService)
        {
            _bikeManagerService = bikeManagerService;
            _bikes = _bikeManagerService.Bikes;
        }
    }
}

自行车列表实际发起的服务一直嵌套在服务类中:

namespace Keiser.MPM.Screen.Core.Models.Bikes
{
    using System;
    using System.Linq;
    using System.Threading;
    using System.Collections.Generic;
    using Cirrious.CrossCore;
    using Cirrious.CrossCore.Core;
    using Cirrious.MvvmCross.ViewModels;
    using Cirrious.MvvmCross.Plugins.Messenger;
    using Core.Models.Settings;

    public class BikeManagerService : MvxNotifyPropertyChanged, IBikeManagerService
    {
        public object BikesLocker = new object();
        private List<Bike> _bikes = new List<Bike>();
        public List<Bike> Bikes
        {
            get { return _bikes; }
            set { _bikes = value;  RaisePropertyChanged(() => Bikes); }
        }

        // --- Other boring code...
    }
}

这是问题所在。如果加载视图时列表为空,则网格视图根本不会动态填充。如果我进入填充了列表的页面,它将正确加载,并且将为添加到列表中的新对象添加网格,但是在我点击屏幕之前它不会从列表中删除已处理的网格。对象继续正确更新,直到放置对象为止。然后对象的字段停止工作,但它们不会消失。此外,如果列表再次变为空,则视图将不会再次更新。

我错过了什么吗?我应该使视图无效吗?任何帮助或资源将不胜感激!

[=======================解决方案=================== ====]

最终的解决方案是将列表转换为可观察的集合: 接口:

namespace Keiser.MPM.Screen.Core.Models.Helpers
{
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;

    public interface IObservableCollection<T>
        : IList<T>
          , INotifyPropertyChanged
          , INotifyCollectionChanged
    {
    }
}

类别:

namespace Keiser.MPM.Screen.Core.Models.Helpers
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;

    public class SimpleObservableCollection<T>
        : ObservableCollection<T>
        , IObservableCollection<T>
    {
        public SimpleObservableCollection(List<T> source) : base(source) { }

        protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);
        }
    }
}

对集合所做的所有更改都必须在主UI线程上完成,这开始降低性能(我猜测来自连续的上下文切换?)。我最终废弃了Observable列表并实现了一个IEnumerable类,它触发了有关更改的消息并在视图中订阅了消息:

namespace Keiser.MPM.Screen.Droid.Views
{
    using Android.App;
    using Android.Widget;
    using Cirrious.MvvmCross.Plugins.Messenger;

    [Activity(Theme = "@style/Theme.FullScreen")]
    public class BikeAssignmentView : BaseView
    {
        protected MvxSubscriptionToken _BikeListToken;

        protected override void OnCreate(Android.OS.Bundle bundle)
        {
            base.OnCreate(bundle);
            this.SetContentView(Resource.Layout.BikeAssignmentView_Page);
            var gridView = FindViewById<GridView>(Resource.Id.gridview);

            _BikeListToken = Cirrious.CrossCore.Mvx.Resolve<IMvxMessenger>().SubscribeOnMainThread<Core.Models.Bikes.BikesChangedMessage>(message =>
            {
                ((BaseAdapter)gridView.Adapter).NotifyDataSetChanged();
            });
        }
    }
}

1 个答案:

答案 0 :(得分:1)

普通Mvvm和数据绑定使用INotifyPropertyChanged

这意味着,当用户界面中的网格将其ItemsSource绑定到Bikes上的BikeAssignmentViewModel时,它会挂钩PropertyChanged上的BikeAssignmentViewModel事件< / p>

由于您从RaisePropertyChanged开始Service,而不是从ViewModel开始,因此网格永远不会看到此更改通知。

解决这个问题:

  • 你可以找到一种方法从ViewModel而不是服务
  • 提出RaisePropertyChange来电
  • 你可以找到一种方法将网格绑定到服务而不是ViewModel(例如绑定ItemsSource Service.Books

如果您是数据绑定的新手,那么也可能值得阅读有关数据绑定的更多内容以及了解ObservableCollection和INotifyCollectionChanged的列表