【问题标题】:How do you do proper binding and updating of Xamarin.Forms ListView?您如何正确绑定和更新 Xamarin.Forms ListView?
【发布时间】:2014-09-20 04:10:10
【问题描述】:

使用 MVVM 模式,我有一个模型、视图模型和视图,其中包含一个列表视图。 ListView 绑定到 ViewModel 的成员,该成员是 Model 类的 ObservableCollection。我可以使初始显示的绑定起作用,并且可以在对视图执行操作时更新模型类上的属性以获取适当的行,但是我无法刷新视图,从 ObservableCollection 中的模型类中提取数据。 ListView 类不包含无效或强制刷新的方法,这将解决我的问题。更新模型上的数据后如何让 ListView 刷新?

下面是我想要做的一个简单示例:每一行都包含一个按钮和标签。单击按钮后,我可以更新标签,这将反映在屏幕上。我需要做的是更新模型,这反过来又会强制更新视图。但是,我无法让它发挥作用。在实际应用中,Model的更新是在业务逻辑层,而不是在视图中,之后需要强制刷新ListView。

示例代码:

using System;
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace ListViewTest
{   
    public class Model
    {
        public static int ids = 0;
        public Model(string count) 
        {
            Id = +1;
            Count = count;
        }
        public int Id { get; set; }
        public string Count { get; set; }
    }

    public class ModelList : ObservableCollection<Model>
    {
    }

    public class ViewModel
    {
        ModelList list = new ModelList();
        public ModelList ViewModelList
        {
            get { return list; }
            set 
            { 
                list = value; 
            }
        }
    }

    public partial class MainPage : ContentPage
    {   
        public ViewModel viewModel;

        public class DataCell : ViewCell
        {
            public DataCell()
            {
                var Btn = new Button();
                Btn.Text = "Click";
                var Data = new Label();
                Data.SetBinding(Label.TextProperty,"Count");
                Btn.Clicked += (object sender, EventArgs e) => 
                {
                    Model model = (Model)(((Button)sender).Parent.BindingContext);
                    int count = Convert.ToInt32(model.Count);
                    count++;
                    model.Count = count.ToString();

                    // Need to refresh ListView from data source here... How???
                };

                StackLayout s = new StackLayout();
                s.Orientation = StackOrientation.Horizontal;
                s.Children.Add(Btn);
                s.Children.Add(Data);
                this.View = s;
            }
        }

        public MainPage ()
        {
            viewModel = new ViewModel();
            viewModel.ViewModelList.Add(new Model("0"));
            viewModel.ViewModelList.Add(new Model("0"));
            InitializeComponent();
        }

        public void InitializeComponent()
        {
            ListView listView = new ListView
            {
                ItemsSource = viewModel.ViewModelList,
                ItemTemplate = new DataTemplate(() =>
                    {
                        return new DataCell();
                    })
            };
            Content = listView;
        }
    }
}

【问题讨论】:

    标签: c# listview data-binding observablecollection xamarin.forms


    【解决方案1】:

    我认为您的模型需要实现 INotifyPropertyChanged。所以 UI 知道模型中的一个值已经改变了

    类似这样的:

    public class Model : INotifyPropertyChanged
    {
        // boiler-plate
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        protected bool SetField<T>(ref T field, T value, string propertyName)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    
        // props
        private string _count;
        public string Count 
        {
            get { return _count; }
            set { SetField(ref _count, value, "Count"); }
        }
    }
    

    【讨论】:

      【解决方案2】:

      从 ViewModelList 属性中删除“set”方法。每当您使用 ObservableCollection 时,只需更改该集合中的项目即可。永远不要用另一个 ObservableCollection 替换它。

      【讨论】: