更新ObservableCollection列表

时间:2016-11-08 09:41:07

标签: c# web-services xamarin prism

我尝试使用从OnNavigatedTo获取的参数将数据从Web服务加载到sfDataGrid

首先它将一个虚拟行加载到网格中,因为我无法获取数据OnNavigatedTo然后它运行OnNavigatedTo并从Web服务获取数据并将数据添加到网格将ItemsSource设置为的ObservableCollection中

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

namespace PrismUnityApp2.ViewModels
{

public class HovedsideViewModel : BindableBase, INotifyPropertyChanged , INavigationAware
{
    MobileService.VaksServiceClient ws = new MobileService.VaksServiceClient();
    INavigationService _navigationService;
    public event PropertyChangedEventHandler PropertyChanged;


    private DateTime selectedDate;
    public DateTime SelectedDate
    {
        get { return selectedDate; }
        set
        {
            if (selectedDate != value)
            {
                selectedDate = value;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this,
                        new PropertyChangedEventArgs("SelectedDate"));
                }
            }
        }
    }

    private DateTime minimumSelectedDate;
    public DateTime MinimumSelectedDate
    {
        get { return minimumSelectedDate; }
        set
        {
            if (minimumSelectedDate != value)
            {
                minimumSelectedDate = value;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this,
                        new PropertyChangedEventArgs("MinimumSelectedDate"));
                }
            }
        }
    }

    public DelegateCommand Navigatetest { get; private set; }
    public DelegateCommand NavigateToBestilling { get; private set; }

    public string latitude { get; set; }
    private string _longitude;

    public string longitude
    {
        get { return _longitude; }
        set
        {
            _longitude = value;
            ws.GetToemmeDatasAsync(latitude, longitude, DateTime.Today.AddDays(-7)); // needs to be set to the 1 of november as its the only day with data
        }
    }




    public HovedsideViewModel(INavigationService navigationService)
    {
        try
        {
            toemmeListe = new ObservableCollection<ToemningData>();
        }
        catch (Exception ex)
        {

            throw;
        }
          SetRowData();

        MinimumSelectedDate = DateTime.Now;
        SelectedDate = DateTime.Now.AddDays(1);

        _navigationService = navigationService;
        Navigatetest = new DelegateCommand(Navigate);
        NavigateToBestilling = new DelegateCommand(_NavigateToBestilling);
    }



    private void _NavigateToBestilling()
    {
        _navigationService.NavigateAsync("Bestilling");
    }

    private void Navigate()
    {
        _navigationService.NavigateAsync("Scanner");
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public void OnNavigatedTo(NavigationParameters parameters)
    {
        latitude = parameters["lat"].ToString();  // if the phone inst near latitude "55,7070631" and longitude "12,4235393" then remove the part where it gets data from parameters
        longitude = parameters["lon"].ToString();  // and use the two lines under this
        //latitude = "55,7070631";
        //longitude = "12,4235393";
    }

    public void SetRowData()
    {
        ws.GetToemmeDatasCompleted += Ws_GetToemmeDatasCompleted;
        ws.GetToemmeDatasAsync(latitude, longitude, DateTime.Today.AddDays(-7));   // needs to be set to the 1 of november as its the only day with data 
    }


    private void Ws_GetToemmeDatasCompleted(object sender, MobileService.GetToemmeDatasCompletedEventArgs e)
    {

        int numOfRows = 0;
        try
        {
            numOfRows = e.Result.Count();   // awdawd
        }
        catch (Exception)
        {
            numOfRows = 0;
        }
        //ToemmeListe.Clear();
        if (numOfRows > 0)
        {
            foreach (var toemming in e.Result)
            {
                ToemningData _ToemningData = new ToemningData();
                _ToemningData.Fraktion = toemming.Fraktion;
                _ToemningData.ToemmeID = toemming.ToemmeId;
                _ToemningData.Type = toemming.type;
                _ToemningData.Vaegt = toemming.weight;
                ToemmeListe.Add(_ToemningData);  // failes when it trys to add a new row   // An unhandled exception occured.
            }
        }
        else  // if there isnt any data then set one row saying that there isnt any data
        {
            ToemningData _ToemningData = new ToemningData();  
            _ToemningData.Fraktion = "Igen Data";
            _ToemningData.ToemmeID = -1;
            _ToemningData.Type = "Igen Data";
            _ToemningData.Vaegt = "Igen Data";
            ToemmeListe.Add(_ToemningData);
        }
    }

    private ObservableCollection<ToemningData> toemmeListe;

    public ObservableCollection<ToemningData> ToemmeListe
    {
        get { return toemmeListe; }
        set { this.toemmeListe = value; }
    }

    }
}

XAML

    <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             xmlns:sfgrid="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms"
             x:Class="PrismUnityApp2.Views.Hovedside"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             Title="test">

  <ContentPage.Content>

    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="20" />
        <RowDefinition Height="50"/>
        <RowDefinition  Height="*" />
        <RowDefinition Height="50" />
        <RowDefinition Height="50" />
      </Grid.RowDefinitions>

      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>

      <DatePicker Date="{Binding SelectedDate,Mode=TwoWay}" MinimumDate="{Binding MinimumSelectedDate,Mode=TwoWay}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" HorizontalOptions="Center">
        <DatePicker.Format>yyyy-MM-dd</DatePicker.Format>
      </DatePicker>



      <sfgrid:SfDataGrid x:Name="dataGrid"
                  AutoGenerateColumns="False"
                  ColumnSizer="Star"
                  SelectedIndex="1"
                  SelectionMode="Single"
                 ItemsSource="{Binding ToemmeListe}"
                   AllowSorting="True"
                          Grid.Row="2" 
                          Grid.Column="0" Grid.ColumnSpan="3"
                         >

        <sfgrid:SfDataGrid.Columns x:TypeArguments="syncfusion:Columns">
          <sfgrid:GridTextColumn HeaderText="Fraktion"
                                     MappingName="Fraktion" />     <!--Fraktion-->                                               
          <sfgrid:GridTextColumn HeaderText="Type"
                                     MappingName="Type" />          <!--Type--> 
          <sfgrid:GridTextColumn HeaderText="Vaegt"
                                   MappingName="Vaegt" />     <!--vægt-->
        </sfgrid:SfDataGrid.Columns>

      </sfgrid:SfDataGrid>

      <Button Text="Scan" FontSize="24" Grid.Row="3" Grid.Column="0" Command="{Binding Navigatetest}"/>
      <Button Text="Mail" FontSize="24" Grid.Row="3" Grid.Column="2"/>
      <Button Text="Manuel" FontSize="24" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" HorizontalOptions="Center" Command="{Binding NavigateToBestilling}"/>

    </Grid>


  </ContentPage.Content>

</ContentPage>

从Web服务获取数据后进入Ws_GetToemmeDatasCompleted时,它停在ToemmeListe.Add(_ToemningData); 在

foreach (var toemming in e.Result)
            {
                ToemningData _ToemningData = new ToemningData();
                _ToemningData.Fraktion = toemming.Fraktion;
                _ToemningData.ToemmeID = toemming.ToemmeId;
                _ToemningData.Type = toemming.type;
                _ToemningData.Vaegt = toemming.weight;
                ToemmeListe.Add(_ToemningData);  // failes when it trys to add a new row   // An unhandled exception occured.
            }

并说出现了未处理的异常。

非常感谢任何帮助

即时通讯使用visual studio 2015社区,xamarin,prism v6.2.0 Xam.Plugin.Geolocator v3.0.4和Syncfusion 主要在Android版6.0.1和使用的sony xperia z3上运行它 API 23

Dropbox link to the full project

我的解决方案

    using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using PrismUnityApp2.ProxyClient;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;

namespace PrismUnityApp2.ViewModels
{


    public class HovedsideViewModel : BindableBase, INotifyPropertyChanged, INavigationAware
    {
        MobileService.VaksServiceClient ws = new MobileService.VaksServiceClient();
        INavigationService _navigationService;
        public event PropertyChangedEventHandler PropertyChanged;


        private DateTime selectedDate;
        public DateTime SelectedDate
        {
            get { return selectedDate; }
            set
            {
                if (selectedDate != value)
                {
                    selectedDate = value;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this,
                            new PropertyChangedEventArgs("SelectedDate"));
                    }
                }
            }
        }

        private DateTime minimumSelectedDate;
        public DateTime MinimumSelectedDate
        {
            get { return minimumSelectedDate; }
            set
            {
                if (minimumSelectedDate != value)
                {
                    minimumSelectedDate = value;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this,
                            new PropertyChangedEventArgs("MinimumSelectedDate"));
                    }
                }
            }
        }

        public DelegateCommand Navigatetest { get; private set; }
        public DelegateCommand NavigateToBestilling { get; private set; }

        public string latitude { get; set; }
        private string _longitude;

        public string longitude
        {
            get { return _longitude; }
            set { _longitude = value; }
        }




        public HovedsideViewModel(INavigationService navigationService)
        {

            SetRowData(); // initialize the grid

            MinimumSelectedDate = DateTime.Now;  // this one will be revmoved later. its fine that they can go back and watch but not edite it
            SelectedDate = DateTime.Now.AddDays(1);

            _navigationService = navigationService;
            Navigatetest = new DelegateCommand(Navigate);
            NavigateToBestilling = new DelegateCommand(_NavigateToBestilling);
        }



        private void _NavigateToBestilling()
        {
            _navigationService.NavigateAsync("Bestilling");
        }

        private void Navigate()
        {
            _navigationService.NavigateAsync("Scanner");
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public async void OnNavigatedTo(NavigationParameters parameters)
        {
            Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
            {
                latitude = parameters["lat"].ToString();  // if the phone inst near latitude "55,7070631" and longitude "12,4235393" then remove the part where it gets data from parameters
                longitude = parameters["lon"].ToString();  // and use the two lines under this
                                                           //latitude = "55,7070631";
                                                           //longitude = "12,4235393";
                var ggg = await CallService(new MobileService.Toemning { Latitude = latitude, Longitude = longitude, date = new DateTime(2016, 11, 1) });  // the date is set to a day where there is data
                var justatest = 0;
                ToemmeListe.Clear();
                foreach (var toemming in ggg)
                {

                    ToemningData _ToemningData = new ToemningData();
                    _ToemningData.Fraktion = toemming.Fraktion;
                    _ToemningData.ToemmeID = toemming.ToemmeId;
                    _ToemningData.Type = toemming.Type;
                    _ToemningData.Vaegt = toemming.Weight;
                    ToemmeListe.Add(_ToemningData);
                }

            });

        }

        MobileService.Toemning ToWCFServiceTodoItem(MobileService.Toemning item)
        {
            return new MobileService.Toemning
            {
                Fraktion = item.Fraktion,
                ToemmeId = item.ToemmeId,
                Type = item.Type,
                date = item.date,
                Latitude = item.Latitude,
                Longitude = item.Longitude,
                Weight = item.Weight
            };
        }


        public async Task<ObservableCollection<MobileService.Toemning>> CallService(MobileService.Toemning item)
        {
            var todoItem = ToWCFServiceTodoItem(item);
            MobileService.VaksServiceClient client = new MobileService.VaksServiceClient(new BasicHttpBinding(), new EndpointAddress("http://vf-kssweb2/Vaks2Svc/VaksService.svc?singleWsdl"));
            var t = Task<ObservableCollection<MobileService.Toemning>>.Factory.FromAsync(
                    ((MobileService.IVaksService)client.InnerChannel).BeginGetToemmeDatas,
                    ((MobileService.IVaksService)client.InnerChannel).EndGetToemmeDatas,
                     todoItem, TaskCreationOptions.None);
            return await t;
        }

        public void SetRowData()
        {

            try
            {
                toemmeListe = new ObservableCollection<ToemningData>();
            }
            catch (Exception ex)
            {

                throw;
            }

            ToemningData _ToemningData = new ToemningData();
            _ToemningData.Fraktion = "Igen Data";
            _ToemningData.ToemmeID = -1;
            _ToemningData.Type = "Igen Data";
            _ToemningData.Vaegt = "Igen Data";
            ToemmeListe.Add(_ToemningData);
        }

        private ObservableCollection<ToemningData> toemmeListe;

        public ObservableCollection<ToemningData> ToemmeListe
        {
            get { return toemmeListe; }
            set { this.toemmeListe = value; }
        }




    }
}

1 个答案:

答案 0 :(得分:0)

您不允许从任何线程更改ObservableCollection,而是创建它的线程(通常是UI线程)。您必须将Add操作重新编组回该主题,最好使用async / await

private async Task FillList()
{
    // on the ui thread here...

    // leaving it to wait for i/o operations or cpu-bound work on a threadpool thread
    var data = await _server.FetchData();

    // here we are back on the ui thread and update the list
    foreach (var item in data)
        TransformItemAndAddItToTheList( item );
}