【问题标题】:Custom ListView binding not working in Xamarin.Forms自定义 ListView 绑定在 Xamarin.Forms 中不起作用
【发布时间】:2020-02-06 10:34:54
【问题描述】:

我正在尝试将响应绑定到 Xamarin.Forms 中的自定义 ListView,但即使 ObservableCollection 包含结果,ListView 仍保持空白。请在下面的代码中指出我的错误。

在下面的代码中,我试图达到以下结果 -

  • 对从 Firebase 收到的响应进行序列化,然后根据响应创建自定义日历。
  • 为了创建日历,我使用了一个模型,该模型将包含要在视图中显示的所有必要绑定。例如颜色、标题、计数等。

我正在使用 Prism MVVM 架构来构建应用程序。

查看

<ListView  ItemsSource="{Binding ListItems}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Frame BorderColor="LightGray" Padding="5">
                        <StackLayout Orientation="Horizontal">
                            <!--<BoxView BackgroundColor="{Binding HighlightColor}" WidthRequest="10"/>-->
                            <Label Text="{Binding Date}" FontSize="Medium" Margin="20,0,0,0"/>
                            <Label Text="{Binding Day}" FontSize="Medium" Margin="20,0,0,0"/>
                            <Label Text="{Binding LeaveCount}" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End"/>
                        </StackLayout>
                    </Frame>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

视图模型

public ObservableCollection<CalendarItem> ListItems { get; set; }    



public LeaveViewerPageViewModel(INavigationService navigationService, IFirebaseService firebaseService)
            : base(navigationService, firebaseService)
        {
            Title = "View Leaves";
            ViewCommand = new DelegateCommand(ViewLeaves);
        }

    private async void ViewLeaves()
    {
        ListItems = new ObservableCollection<CalendarItem>();

        var x = await FirebaseService.GetAll(_month, _year);

        foreach (var item in x)
        {
            ListItems.Add(item);
        }
    }

服务

public async Task<List<CalendarItem>> GetAll( string month, string year)
{
    List<CalendarItem> ItemList = new List<CalendarItem>();

    int iterationLimit = DateTime.DaysInMonth(int.Parse(year), (DateTime.ParseExact(month.Substring(0, 3), "MMM", CultureInfo.InvariantCulture)).Month);

    for (int i = 1; i <= iterationLimit; i++)
    {
       CalendarItem ITEM = new CalendarItem();

        DateTime dateTime = new DateTime(int.Parse(year), DateTime.ParseExact(month.Substring(0, 3), "MMM", CultureInfo.InvariantCulture).Month, i);
        var res = await GetLeavesAsync(i, month, year);

        ITEM.Date = dateTime.Day.ToString();
        ITEM.Day = dateTime.DayOfWeek.ToString();
        ITEM.LeaveCount = res.Count;
        ITEM.Leaves = res;
        if (res.Count > 0)
            ITEM.HighlightColor = res.Count < 5 ? System.Drawing.Color.Yellow : System.Drawing.Color.Tomato;

        ItemList.Add(ITEM);
    }

    return ItemList;
}

型号

 public class CalendarItem
    {
        public Color HighlightColor { get; set; }
        public string Date { get; set; }
        public string Day { get; set; }
        public int LeaveCount { get; set; }
        public List<LeaveDetail> Leaves { get; set; }
    }

【问题讨论】:

    标签: xamarin mvvm xamarin.forms prism


    【解决方案1】:

    根据您在此处的代码,实际上存在几个问题:

    1) ViewModel 中的 ListItems 属性本身并未实现 INotifyPropertyChanged。

    public class ViewAViewModel : BindableBase
    {
        private ObservableCollection<CalendarItem> _listItems;
        public ObservableCollection<CalendarItem> ListItems
        {
            get => _listItems;
            set => SetProperty(ref _listItems, value);
        }
    }
    

    2) 您正在 ViewLeaves 方法中新建一个 ListItems,然后一次添加一个项目。这里的结果是,如果您在设置 ListItems 时遵循第一步,它会尝试更新 UI,然后每次添加项目时它都会尝试更新 UI。

    3) 您有两种优化方法:

    • 使用 James Montemagno 在他的 MvvmHelpers 库中的 ObservableRangeCollection。这将允许您在 ctor 中新建集合,然后简单地将集合转储到:
    private async void ViewLeaves()
    {
        ListItems.ReplaceRange(await FirebaseService.GetAll(_month, _year));
    }
    
    • 只需实现我指出的第一个问题中所示的属性,但将其更改为 IEnumerable&lt;CalendarItem&gt; 并将其设置为:
    private async void ViewLeaves()
    {
        ListItems = await FirebaseService.GetAll(_month, _year);
    }
    

    【讨论】:

    • 请参考我在学习 MVVM 时参考的这个链接。 github.com/AsfendTheMVP/MVVM-Prism/blob/master/… 即使没有实现 INotifyPropertyChanged,ObservableCollection 也能正常工作。请帮助我了解它与我目前的情况有何不同?
    【解决方案2】:

    请尝试如下修改您的 ListItems:-

        private ObservableCollection<CalendarItem> _listItems = new ObservableCollection<CalendarItem>();
        public ObservableCollection<CalendarItem> ListItems
        {
            get => _listItems;
            set => SetProperty(ref _listItems, value);
        }
    

    【讨论】:

      最近更新 更多