【问题标题】:How to retrieve text of entry cell of custom cell in a list view in Xamarin.Forms如何在 Xamarin.Forms 的列表视图中检索自定义单元格的条目单元格的文本
【发布时间】:2016-03-27 00:13:57
【问题描述】:

我是 Xamarin.Forms 的新手,我创建了一个包含 4 个标签和 1 个条目的自定义单元格的列表。我设法显示标签和条目。但我想使用条目单元格中的文本。怎么做?我的用户界面就像this

下面是代码模型

public class DSO_beat_Retailer_mapping
{
    [PrimaryKey, AutoIncrement]
    public int _id{ get; set;}
    public string DSO_CD{ get; set;}
    public string Beat_id{ get; set;}
    public string Retailer_cd{ get; set;}
    public string Retailer_nm{ get; set;}
    public string email{ get; set;}
    public string mobile{ get; set;}
    public DateTime birth_dt{ get; set;}
    public DateTime Anniversary_dt{ get; set;}
    public DateTime Lst_sync_dt{ get; set;}

}

下面是页面

public class RetailerListPage : ContentPage
{
    public RetailerListPage()
    {
        BackgroundColor = Color.White;
        Title = "Retailer List";

        CreateNewDB database = new CreateNewDB();
        database.saveDSOReatilMap(retailerlst);

        // Fetch data from LOCAL TABLE DSO_beat_Retailer_mapping
        List<DSO_beat_Retailer_mapping> RetailerList = database.GetDSOReatilMap("Select * from DSO_beat_Retailer_mapping ").ToList();

        ListView listview = new ListView();
        listview.RowHeight = 100;
        listview.ItemsSource = RetailerList;
        listview.ItemTemplate = new DataTemplate(typeof(CustomCell));  

        this.Content = listview;
    }

public class CustomCell : ViewCell
    {
        public CustomCell()
        {
    //Please Condider 4 labes & 1 Entry cell is created though below code have 1 label & 1 entry

            AbsoluteLayout cellView = new AbsoluteLayout();
            var retailernameLabel = new Label();
            AbsoluteLayout.SetLayoutBounds(retailernameLabel, new Rectangle(5, 12 , AbsoluteLayout.AutoSize,AbsoluteLayout.AutoSize));
            retailernameLabel.SetBinding(Label.TextProperty, new Binding("Retailer_nm"));
            retailernameLabel.FontSize = 18;
            retailernameLabel.TextColor = Color.FromHex("#434343");
            cellView.Children.Add(retailernameLabel);

    //Remaining 3 labels goes here

            var txtAmt = new Entry();
            AbsoluteLayout.SetLayoutBounds(txtAmt, new Rectangle(5, 32, 500, 60));
            txtAmt.SetBinding(Entry.TextProperty, new Binding("inputAmt"));
            txtAmt.Keyboard = Keyboard.Numeric;
            txtAmt.TextColor = Color.Black;
            cellView.Children.Add(txtAmt);

            this.View = cellView;

            View = new StackLayout()
            {
                BackgroundColor = rowcolor,
                Children = { cellView }
            };

        }
    }

}

另外请说明上述代码中的错误以及绑定数据的正确方法。

代码更改如下

public class RetailerListPage : ContentPage
{
    public RetailerListPage()
    {
        BackgroundColor = Color.White;
        Title = "Retailer List";

        BindingContext = new RetailerListPageViewModel();

        ListView listview = new ListView();
        listview.RowHeight = 100;

        listview.ItemTemplate = new DataTemplate(typeof(CustomCell));

        listview.SetBinding(ListView.ItemsSourceProperty, "RetailerList");

        Content = listview;
    }

    public class CustomCell : ViewCell
    {
        public CustomCell()
        {
           #region Code that Customizes Cell

            AbsoluteLayout cellView = new AbsoluteLayout();
            var retailernameLabel = new Label();
            AbsoluteLayout.SetLayoutBounds(retailernameLabel, new Rectangle(5, 12, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
            retailernameLabel.SetBinding(Label.TextProperty, new Binding("Retailer_nm"));
            retailernameLabel.FontSize = 18;
            retailernameLabel.TextColor = Color.FromHex("#434343");
            cellView.Children.Add(retailernameLabel);

            var txtAmt = new Entry();
            AbsoluteLayout.SetLayoutBounds(txtAmt, new Rectangle(5, 32, 500, 60));
            txtAmt.SetBinding(Entry.TextProperty, new Binding("InputAmt"));
            txtAmt.Keyboard = Keyboard.Numeric;
            txtAmt.TextColor = Color.Black;
            cellView.Children.Add(txtAmt);

            this.View = cellView;

            View = new StackLayout()
            {
              Children = { cellView }
            };
            #endregion
        }
    }

}

在Model中新增inputAmt属性如下

public class DSO_beat_Retailer_mapping: INotifyPropertyChanged
{
    public string _inputAmt;  //NEWLY ADDED
    public int _id;
    public string _DSO_CD;
    public string _Beat_id;
    public string _Retailer_cd;
    public string _Retailer_nm;
    public string _email;
    public string _mobile;
    public DateTime _birth_dt;
    public DateTime _Anniversary_dt;
    public DateTime _Lst_sync_dt;
    public string InputAmt
    {
        get
        {
            return _inputAmt;
        }

        set
        {
            _inputAmt = value;
            OnPropertyChanged("inputAmt");
        }
    }

    public int Id
    {
        get
        {
            return _id;
        }

        set
        {
            _id = value;
            OnPropertyChanged("ID");
        }
    }

    public string DSO_CD
    {
        get
        {
            return _DSO_CD;
        }

        set
        {
            _DSO_CD = value;
            OnPropertyChanged("DSO_CD");
        }
    }

    public string Beat_id
    {
        get
        {
            return _Beat_id;
        }

        set
        {
            _Beat_id = value;
            OnPropertyChanged("Beat_id");
        }
    }

    public string Retailer_cd
    {
        get
        {
            return _Retailer_cd;
        }

        set
        {
            _Retailer_cd = value;
            OnPropertyChanged("Retailer_cd");
        }
    }

    public string Retailer_nm
    {
        get
        {
            return _Retailer_nm;
        }

        set
        {
            _Retailer_nm = value;
            OnPropertyChanged("Retailer_nm");
        }
    }

    public string email
    {
        get
        {
            return _email;
        }

        set
        {
            _email = value;
            OnPropertyChanged("email");
        }
    }

    public string mobile
    {
        get
        {
            return _mobile;
        }

        set
        {
            _mobile = value;
            OnPropertyChanged("mobile");
        }
    }

    public DateTime birth_dt
    {
        get
        {
            return _birth_dt;
        }

        set
        {
            _birth_dt = value;
            OnPropertyChanged("birth_dt");
        }
    }

    public DateTime Anniversary_dt
    {
        get
        {
            return _Anniversary_dt;
        }

        set
        {
            _Anniversary_dt = value;
            OnPropertyChanged("Anniversary_dt");
        }
    }

    public DateTime Lst_sync_dt
    {
        get
        {
            return _Lst_sync_dt;
        }

        set
        {
            _Lst_sync_dt = value;
            OnPropertyChanged("Lst_sync_dt");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, e);
        }
    }
}

而ViewModel如下

 public class RetailerListPageViewModel : INotifyPropertyChanged
{
    private List<DSO_beat_Retailer_mapping> retailerList;

    public RetailerListPageViewModel()
    {
        #region Here data inserted for test purpose 
        //DSO_beat_Retailer_mapping retailerlst = new DSO_beat_Retailer_mapping
        //{
        //    InputAmt = "200",
        //    _id = 1,
        //    DSO_CD = "123",
        //    Beat_id = "111",
        //    Retailer_nm = "XYZ RETAILER",
        //    email = "ZYZ@ABCD.com",
        //    mobile = "1234567890",
        //    birth_dt = DateTime.Now,
        //    Anniversary_dt = DateTime.Now,
        //    Lst_sync_dt = DateTime.Now
        //};

        //DSO_beat_Retailer_mapping retailerlst1 = new DSO_beat_Retailer_mapping
        //{
        //    InputAmt = "200",
        //    _id = 1,
        //    DSO_CD = "123",
        //    Beat_id = "111",
        //    Retailer_cd = "R123",
        //    Retailer_nm = "XYZ RETAILER",
        //    email = "ZYZ@ABCD.com",
        //    mobile = "1234567890",
        //    birth_dt = DateTime.Now,
        //    Anniversary_dt = DateTime.Now,
        //    Lst_sync_dt = DateTime.Now
        //};
        #endregion

        CreateNewDB database = new CreateNewDB();
        //database.saveDSOReatilMap(retailerList);  
        //database.saveDSOReatilMap(retailerlst1);

       RetailerList = database.GetDSOReatilMap("Select * from DSO_beat_Retailer_mapping ").ToList();
    }

        public List<DSO_beat_Retailer_mapping> RetailerList
    {
        get { return retailerList; }

        set
        {
            retailerList = value;
            OnPropertyChanged("RetailerList");
        }
    }

    public Command btnSave
    {
        get
        {
            return new Command(() => {
                // Code to save List 

            });
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, e);
        }
    }
}

以下CreateNewDB 是访问数据库的类

public class CreateNewDB
{
    static object locker = new object ();
    SQLiteConnection database;

    public CreateNewDB ()
    {

        database = DependencyService.Get<ISQLite> ().GetConnection ();

        database.DropTable<DSO_beat_Retailer_mapping> ();
        database.CreateTable<DSO_beat_Retailer_mapping> ();
    }


    //DSO_beat_Retailer_mapping
    public IEnumerable<DSO_beat_Retailer_mapping> GetDSOReatilMap(string query)
    {
        lock (locker) {
            return database.Query<DSO_beat_Retailer_mapping> (query);
        }
    }

    public string saveDSOReatilMap(DSO_beat_Retailer_mapping item)
    {
        lock (locker) {
            database.Insert(item);
            return item.Retailer_cd;
        }
    }
//UPDATE DB  
public string UpdateDSOReatilMap(DSO_beat_Retailer_mapping item)
    {
        lock (locker)
        {
            database.Update(item);
            return item.Retailer_cd;
        }
    }
    public int DeleteDSOReatilMap(string empcd)
    {
        lock (locker) {
            return database.Delete<DSO_beat_Retailer_mapping> (empcd);
        }
    }


}

我的问题是:

  1. 仍然无法填充列表
  2. 我需要在RetailerListPage 上添加下一个按钮(如附图所示),以便在下一页上使用详细信息。
  3. 无法更新数据库中的详细信息,即(金额)

请指导。

【问题讨论】:

  • 向我们展示与问题相关的代码以及到目前为止您实际尝试过的内容
  • @ArkadiuszK 请查看更新和指南
  • 您是否包括对RetailerListPageViewModel 的修改,即关于RetailerList 属性的修改?除了填充列表之外,您的其他问题与您提出的问题无关。我认为您必须为他们创建单独的问题。
  • 您没有包含RetailerListPageViewModel 的代码。这就是我问的原因。
  • 我很抱歉。我也在 ViewModel 中粘贴了相同的代码模型。但现在我对帖子进行了更正。

标签: listview xamarin xamarin.forms


【解决方案1】:

Xamarin.Forms 中广泛使用的模式是 MVVM 模式(代表 Model View ViewModel)。它用于将特定的 UI 代码与业务逻辑代码分离。按照该模式创建 ViewModel 类,该类为 View 准备数据并允许将 View 与 Model 连接(因此得名)。重要的部分,它允许实际将 ViewModel 绑定到 View 是 INotifyPropertyChanged 接口。 ViewModel 应该实现这个接口来通知视图 ViewModel 发生的变化。然后,当 ViewModel 中发生某些事情时,它应该引发 OnPropertyChanged 方法,该方法实际上将 notification 发送到视图。另一个重要的部分是视图必须知道哪个 ViewModel 订阅通知。为此,我们使用BindingContext 属性。参考下面的代码,我觉得应该很清楚了。

在您的情况下,我们可以为RetailerListPage 创建RetailerListPageViewModel

public class RetailerListPageViewModel : INotifyPropertyChanged
{
    private List<DSO_beat_Retailer_mapping> retailerList;

    public RetailerListPageViewModel()
    {
        CreateNewDB database = new CreateNewDB();
        database.saveDSOReatilMap(retailerlst);

        // Fetch data from LOCAL TABLE DSO_beat_Retailer_mapping
        RetailerList = database
                               .GetDSOReatilMap("Select * from DSO_beat_Retailer_mapping ")
                               .ToList();
    }


    public List<DSO_beat_Retailer_mapping> RetailerList
    {
        get { return retailerList; }
        set 
        { 
            retailerList = value; 
            OnPropertyChanged("RetailerList");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, e);
        }
    }
}

现在我们可以修改RetailerListPage 以使用我们创建的ViewModel(通过使用BindingContext 属性):

public class RetailerListPage : ContentPage
{
    public RetailerListPage()
    {
       BackgroundColor = Color.White;
       Title = "Retailer List";

       BindingContext = new RetailerListPageViewModel();

       ListView listview = new ListView();
       listview.RowHeight = 100;
       listview.ItemTemplate = new DataTemplate(typeof(CustomCell));

       listview.SetBinding(ListView.ItemsSourceProperty, "RetailerList");  

       this.Content = listview;
    }
}

当您将ListView 绑定到某个数据集合时,每个CustomCell 都会作为BindingContext 从该集合中分配一个项目。你可以认为它现在变成了CustomCell 的 ViewModel。这实际上解释了为什么显示标签的代码有效。因此,您正在尝试将Entry.Text 绑定到inputAmt 属性,但DSO_beat_Retailer_mapping 类中不存在名为inputAmt 的属性。因此,您需要使用该属性和要显示的其他属性创建 ViewModel:

public class BeatRetailerItemViewModel : INotifyPropertyChanged
{
    private string _inputAmt;  
    private string retailerNm;

    public string inputAmt
    {
        get { return _inputAmt; }
        set 
        { 
            _inputAmt= value; 
            OnPropertyChanged("inputAmt");
        }
    }

    public string Retailer_nm 
    { 
        get { return retailerNm; }
        set 
        { 
            retailerNm = value; 
            OnPropertyChanged("Retailer_nm");
        }
    }

    //and other properties that you need to display
    //and INotifyPropertyChanged implementation
}

好的,但我们还没有走出困境。现在我们必须修改RetailerListPageViewModel以使用新的ViewModel(我省略了INotifyPropertyChanged代码,因为你可以在上面的例子中看到它):

public class RetailerListPageViewModel : INotifyPropertyChanged
{
    private List<BeatRetailerItemViewModel> retailerList;

    public RetailerListPageViewModel()
    {
        CreateNewDB database = new CreateNewDB();
        database.saveDSOReatilMap(retailerlst);

        // Fetch data from LOCAL TABLE DSO_beat_Retailer_mapping
        RetailerList = database
                               .GetDSOReatilMap("Select * from DSO_beat_Retailer_mapping ")
                               .Select(x => new BeatRetailerItemViewModel { Retailer_nm = x.Retailer_nm })
                               .ToList();
    }

    public List<BeatRetailerItemViewModel> RetailerList
    {
        get { return retailerList; }
        set 
        { 
            retailerList = value; 
            OnPropertyChanged("RetailerList");
        }
    }

    //INotifyPropertyChanged implementation
}

我希望你看到那里的模式:)

【讨论】:

  • 非常感谢您的宝贵回答。
  • 我忘记在DSO_beat_Retailer_mapping 类中添加属性inputAmt ,但现在我添加了inputAmt。因此,因此无需创建BeatRetailerItemViewModel 对吗?但是现在列表没有显示任何数据:(
  • 是的,你是对的。尽管如此,我在RetailerListPageViewModel 中犯了一个错误,因为集合没有分配给RetailerList 属性。我有固定的代码示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多