簡體   English   中英

Xamarin ListView TwoWay綁定在iOS上不起作用

[英]Xamarin ListView TwoWay binding doesn't work on iOS

在我們的Xamarin應用程序中,我們有一個ListView顯示一個調查列表。如果用戶選擇了一個調查,它們將被帶到該調查詳細信息頁面。 為此,我們在SelectedItem屬性上使用TwoWay綁定,然后向控制器中的SelectedItem屬性添加一個setter。

Xaml-

<ListView x:Name= "surveyList" ItemsSource= "{Binding Surveys}" SelectedItem= "{Binding SelectedSurvey, Mode=TwoWay}" BackgroundColor= "White" HorizontalOptions= "Fill" SeparatorColor= "Gray" RowHeight= "50" >

C#-

private SurveyListItem _selectedSurvey;
public SurveyListItem SelectedSurvey
{
    get { return _selectedSurvey; }
    set
    {
        _selectedSurvey = value;
        if (_selectedSurvey == null)
        {
            NotifyPropertyChanged();
            return;
        }
        OnSurveySelected(_selectedSurvey);
        _selectedSurvey = null;
        NotifyPropertyChanged();
    }
}

這在Android上可以找到,但在iOS上不可用。 點擊列表中的項目不會設置_selectedSurvey或調用SelectedSurvey的設置器。

我可以進行快速修復,並將其更改為某種輕敲手勢,但是在需要進行多選的應用程序的其他地方使用ListView,將所有這些更改為輕敲手勢會很麻煩。

任何想法為什么這將適用於Android但不適用於iOS

編輯-

全Xaml-

<?xml version = "1.0" encoding= "utf-8" ?>

< TabbedPage xmlns = "http://xamarin.com/schemas/2014/forms"

             xmlns:x= "http://schemas.microsoft.com/winfx/2009/xaml"

              x:Class= "MyApp.View.ModuleContentPage"

             xmlns:vm= "clr-namespace:MyApp.ViewModel;assembly=MyApp"

             xmlns:local= "clr-namespace:MyApp.View;assembly=MyApp"

             Title= "Module Content Render" >

  < TabbedPage.Children >

    < ContentPage Title= "Summary" IsEnabled= "False" >

      < ContentPage.Content >

        < StackLayout Padding= "20, 20, 20, 0" >

          < Label Text= "To Do: Render Module Content Here." ></ Label >

        </ StackLayout >

      </ ContentPage.Content >

    </ ContentPage >

    < ContentPage Title= "Related" >

      < ContentPage.Content >

        < StackLayout Padding= "20, 20, 20, 0" >

          < Label Text= "To Do: Render Related Content Here." ></ Label >

        </ StackLayout >

      </ ContentPage.Content >

    </ ContentPage >

    < ContentPage Title= "Surveys" IsEnabled= "False" >

      < ContentPage.Content >

        < StackLayout Padding= "20" >

          < ListView  x:Name= "surveyList" ItemsSource= "{Binding Surveys}" SelectedItem= "{Binding SelectedSurvey, Mode=TwoWay}" BackgroundColor= "White" HorizontalOptions= "Fill" SeparatorColor= "Gray" RowHeight= "50" >

            < ListView.Header >

              < StackLayout Padding= "0, 0, 0, 10" VerticalOptions= "Center" >

                  < Label Text= "Surveys" FontSize= "20" TextColor= "Gray" LineBreakMode= "NoWrap" />

              </ StackLayout >

            </ ListView.Header >

            < ListView.ItemTemplate >

              < DataTemplate >

                < ViewCell >

                  < ViewCell.View >

                    < StackLayout VerticalOptions= "Center" >

                      < Grid ColumnSpacing= "20" >

                        < Grid.RowDefinitions >

                          < RowDefinition Height= "*" />

                        </ Grid.RowDefinitions >

                        < Grid.ColumnDefinitions >

                          < ColumnDefinition Width= "*" />

                          < ColumnDefinition Width= "50" />

                        </ Grid.ColumnDefinitions >

                        < Label Text= "{Binding HydratedSurvey.Name}" FontSize= "12" TextColor= "Black" FontAttributes= "Bold" Grid.Row= "0" Grid.Column= "0" />

                        < Label Text= "{Binding SurveyInstanceCount}" FontSize= "12" TextColor= "Green" FontAttributes= "Bold" Grid.Row= "0" Grid.Column= "1" />

                      </ Grid >

                    </ StackLayout >

                  </ ViewCell.View >

                </ ViewCell >

              </ DataTemplate >

            </ ListView.ItemTemplate >

          </ ListView >

        </ StackLayout >

      </ ContentPage.Content >

    </ ContentPage >

  </ TabbedPage.Children >

</ TabbedPage >

背后的代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace MyApp.View
{
    public partial class ModuleContentPage : TabbedPage
    {
        private Page PreviousPage { get; set; }

        public ModuleContentPage()
        {
            InitializeComponent();

            // TODO hard coded to disabled the first two tabs and select Surveys. Remove when other tabs are finished
            DisableTab(Children[0]);
            DisableTab(Children[1]);

            //Children[0].IsEnabled = false;
            //Children[1].IsEnabled = false;
            //PreviousPage = Children[2];
            //CurrentPage = PreviousPage;
            CurrentPage = Children[2];

            CurrentPageChanged += ModuleContentPage_CurrentPageChanged;
            PagesChanged += ModuleContentPage_PagesChanged;
        }

        private void DisableTab(Page page)
        {
            page.IsEnabled = false;
            //page.Unfocus();
            page.Opacity = 50.0;
        }

        private void ModuleContentPage_PagesChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            CurrentPage = Children[2];
        }

        private void ModuleContentPage_CurrentPageChanged(object sender, EventArgs e)
        {
            CurrentPage = Children[2];
        }
    }
}

**查看模型-**

using Newtonsoft.Json;
using MyApp.DataModel.TransferObjects;
using MyApp.DataAccess.UoW;
using MyApp.Services;
using MyApp.SQLiteAccess.Repository;
using MyApp.SQLiteAccess.Tables;
using MyApp.ViewModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace MyApp.ViewModel
{
    public class SurveyListItem : ViewModelBase
    {
        public SurveyDTO HydratedSurvey { get; set; }
        private int _surveyInstanceCount;
        public int SurveyInstanceCount { get { return _surveyInstanceCount; } set { _surveyInstanceCount = value; NotifyPropertyChanged(); } }
    }

    public class ModuleContentPageViewModel : ViewModelBase
    {
        private ModuleHydratedDTO _module;
        public ModuleHydratedDTO Module { get { return _module; } set { _module = value; NotifyPropertyChanged(); } }

        private ModuleContentHydratedDTO _moduleContent;
        public ModuleContentHydratedDTO ModuleContent { get { return _moduleContent; } set { _moduleContent = value; NotifyPropertyChanged(); } }

        SqlSurveyInstanceRepository _sqlSurveyInstanceRepository;
        SqlSurveyInstanceRepository SqlSurveyInstanceRepository { get { return _sqlSurveyInstanceRepository ?? (_sqlSurveyInstanceRepository = new SqlSurveyInstanceRepository()); } }

        private ObservableCollection<SurveyListItem> _surveys;
        public ObservableCollection<SurveyListItem> Surveys { get { return _surveys; } set { _surveys = value; NotifyPropertyChanged(); } }

        public ModuleContentPageViewModel(ModuleHydratedDTO module, ModuleContentHydratedDTO moduleContent) : base()
        {
            _module = module;
            _moduleContent = moduleContent;
            _surveys = GetSurveys();

            MessagingCenter.Subscribe<Stores.SurveyStore, SurveyDTO>(this, "UpdateSurveyInstanceCount", (sender, hydratedSurvey) =>
            {
                SurveyListItem survey = _surveys.FirstOrDefault(s => s.HydratedSurvey.SurveyId == hydratedSurvey.SurveyId);
                if (survey != null)
                {
                    survey.SurveyInstanceCount = UoW.SurveyInstances.GetCountForSurveyIdAsync(hydratedSurvey.MasterSurveyId ?? hydratedSurvey.SurveyId, ModuleContent.ModuleContentId).Result;
                    NotifyPropertyChanged();
                }
            });
        }

        private ObservableCollection<SurveyListItem> GetSurveys()
        {
            ObservableCollection<SurveyListItem> surveyList = new ObservableCollection<SurveyListItem>();
            List<SurveyDTO> surveys = UoW.Surveys.GetHydratedSurveysForUser(_module.Module.ModuleId);

            if (surveys.Count > 0)
            {
                foreach (var survey in surveys)
                {
                    SurveyListItem item = new SurveyListItem();
                    item.HydratedSurvey = survey;
                    item.SurveyInstanceCount = UoW.SurveyInstances.GetCountForSurveyIdAsync(survey.MasterSurveyId.HasValue ? survey.MasterSurveyId.Value : survey.SurveyId, ModuleContent.ModuleContentId).Result;
                    surveyList.Add(item);
                }
            }
            return surveyList;
        }

        private SurveyListItem _selectedSurvey;
        public SurveyListItem SelectedSurvey
        {
            get { return _selectedSurvey; }
            set
            {
                _selectedSurvey = value;
                if (_selectedSurvey == null)
                {
                    NotifyPropertyChanged();
                    return;
                }
                OnSurveySelected(_selectedSurvey);
                _selectedSurvey = null;
                NotifyPropertyChanged();
            }
        }

        private void OnSurveySelected(SurveyListItem selectedSurvey)
        {
            NavigationService.PushAsync(new SurveyInstanceListVM(selectedSurvey.HydratedSurvey, _moduleContent.ModuleContentId), selectedSurvey.HydratedSurvey.Name);
        }
    }
}

希望能有所幫助

編輯編輯-

這是古怪的viewmodel / viewmodelbase組合。

using MyApp.DataModel.TransferObjects;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using MyApp.ViewModelFramework.Spooling;

namespace MyApp.ViewModel
{
    public class SurveyListItem
    {
        public string Name { get { return "foo"; } set { var x = value; } }
        private int _surveyInstanceCount;
        public int SurveyInstanceCount { get { return _surveyInstanceCount; } set { _surveyInstanceCount = value; } }
    }

    public class ModuleContentPageViewModel
    {
        private ObservableCollection<SurveyListItem> _surveys;
        public ObservableCollection<SurveyListItem> Surveys { get { return _surveys; } set { _surveys = value; NotifyPropertyChanged(); } }


        public ModuleContentPageViewModel(ModuleHydratedDTO module, ModuleContentHydratedDTO moduleContent) : base()
        {
            _surveys = GetSurveys();
        }

        private ObservableCollection<SurveyListItem> GetSurveys()
        {
            ObservableCollection<SurveyListItem> surveyList = new ObservableCollection<SurveyListItem>();
            surveyList.Add(new SurveyListItem());
            return surveyList;
        }

        private SurveyListItem _selectedSurvey;
        public SurveyListItem SelectedSurvey
        {
            get { return _selectedSurvey; }
            set
            {
                _selectedSurvey = value;
                if (_selectedSurvey == null)
                {
                    NotifyPropertyChanged();
                    return;
                }
                _selectedSurvey = null;
                NotifyPropertyChanged();
            }
        }

        public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            InvokeNotifyPropertyChanged(propertyName);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public NotifyPropertyChangedSpooler NotificationSpooler = new NotifyPropertyChangedSpooler();

        private NotificationPropertyChangedStateEnum _notificationPropertyChangedState = NotificationPropertyChangedStateEnum.Active;

        // Gets and sets change notification spooling and blocking features.
        public NotificationPropertyChangedStateEnum NotificationPropertyChangedState
        {
            get { return _notificationPropertyChangedState; }
            set
            {
                _notificationPropertyChangedState = value;
                if (_notificationPropertyChangedState == NotificationPropertyChangedStateEnum.Active && !NotificationSpooler.IsEmpty)
                {
                    NotificationSpooler.Unwind();
                }
                NotifyPropertyChanged();

            }
        }


        void InvokeNotifyPropertyChanged(string propertyName)
        {
            switch (NotificationPropertyChangedState)
            {
                case NotificationPropertyChangedStateEnum.Active:
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                    break;
                case NotificationPropertyChangedStateEnum.Spooling:
                    NotificationSpooler.Enqueue(this, propertyName);
                    break;
                case NotificationPropertyChangedStateEnum.Inactive:
                    break;
            }
        }
    }

    public enum NotificationPropertyChangedStateEnum
    {
        Inactive = 0,
        Active = 1,
        Spooling = 3
    }
}

經過調查發現,該頁面在xaml中被禁用,並且從未在xaml中或在其背后的代碼中均未啟用。 出於某種原因,它在Android中不是問題(這是一種錯誤,應進一步調查原因)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM