简体   繁体   中英

TableView Cells Have Their Data Reset On Scrolling

-----EDIT-----

I've found a workaround to my problem, by utilising the DraggingStarted method inside my TableViewSource. It is not the most optimal solution, and I will continue looking for a proper way to deal with my problem, but for now, I can continue on with my process.

public override void DraggingStarted(UIScrollView scrollView)
{
    for (int i = 0; i < 12; i++)
    {
        try
        {
            GlobalSupport.NewClientData[i] = ((scrollView as UITableView).CellAt(NSIndexPath.FromItemSection(i, 0)).ContentView.Subviews[1] as UITextField).Text;
        }
        catch
        {
        }
    }

    Console.WriteLine("hoi");
}

in my GetCell method, I then search this new data structure, to find the right value:

if (GlobalSupport.NewClientData[indexPath.Row] != "")
{
    cell.cellValue = GlobalSupport.NewClientData[indexPath.Row];
}

-----ENDEDIT-----

I am working on implementing a TableView-focused App. This means that most of my screens are TableViews, that have re-usable cells in them. These cells are defined using the Xcode Designer (this means I have a .cs, a .xib and a .designer in my resources for each different unique cell).

When building up a TableView with pre-defined data (custom data objects, Dictionaries, Lists, etc.) I call methods in my cell's .cs to modify two UILabels (or a UILabel and a UIImageView) defined in the .xib. This all goes well; the data supplied gets put into the labels and other controls, via the GetCell method inside my TableViewSource, and remains there, even after scrolling (since the data is pre-defined, and uses the IndexPath.Row to determine where to be put).

Now comes the trouble:

I have another cell, that has a UILabel and UITextField in it. The UILabel has its text modified to correspond with my localizable strings file. I have a switch in my GetCell method, inside my TableViewSource, that looks like this:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
    CTextInput cell = (CTextInput)tableView.DequeueReusableCell(CTextInput.Identifier);

    switch (indexPath.Row)
    {
        case 0:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtBSN", "", "");
            break;
        case 1:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtPrefix", "", "");
            break;
        case 2:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtInitials", "", "");
            break;
        case 3:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtFirstName", "", "");
            break;
        case 4:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtLastName", "", "");
            break;
        case 5:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtDateOfBirth", "", "");
            cell.Accessory = UITableViewCellAccessory.DetailDisclosureButton;
            break;
        case 6:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtCity", "", "");
            break;
        case 7:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtStreet", "", "");
            break;
        case 8:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtHouseNumber", "", "");
            break;
        case 9:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtZipcode", "", "");
            break;
        case 10:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtCountry", "", "");
            break;
        case 11:
            cell.cellLabel = NSBundle.MainBundle.LocalizedString("txtPhonenumber", "", "");
            break;
        default:
            break;
    }

    return cell;
}

This works great.

Now, when the view's loaded, the user can input his or her data in the UITextField, next to each of these UILabels. Data gets supplied, and as the user progresses down the TableView, all text stays there... Until the user gets to the bottom of the screen, and needs to scroll to view the other cells. What happens then, is that the data supplied in the first few cell's UITextField gets reset to the value, specified in the cell's .xib file, which is "". This is because of the DequeueReusableCell in the beginning of my GetCell method. The GetCell method is being called every time a new cell enters the user's view. This means that all cells that disappear from the user's view, will reset to their default.

Supply the data

Scrolling down

Scrolling back up

I don't want a separate set of .cs, .xib and .designer files for each cell in this view, and have found no method to save contents of a cell's UITextField as of yet. What's more, I need the content of the UITextField inside every cell, in order to create a new object, that I need to further progress this proces.

Any help on this subject is much appreciated. If you need more info, don't hesitate to contact me!

Dear regards, Björn

The DataSource for your UITableView needs to provide the cell with any data it needs to render fully and correctly. Since cells are reused, they can be thought of as "dumb" and rely completely on the data source to know what to display.

Keeping that in mind, what you need to do is update your DataSource to include whatever is inputted into the UITextField for the cell.

Here is an example of how you could accomplish this:

1.) Implement your data source for your UITableView to be key/value pairs:

DataSource = new Dictionary<string, string> () {
    { "Label 1", string.Empty },
    { "Label 2", string.Empty },
    ...
    ...
};

For your scenario "Label 1" would be NSBundle.MainBundle.LocalizedString("txtBSN", "", "")

2.) Implement your CTextInput cell like this:

public partial class CTextInput : UITableViewCell
{
    Action<string, string> OnTextFieldTextChanged;

    public CustomCell ()
    {
    }

    public CustomCell (IntPtr handle) : base (handle)
    {
    }

    public void SetupCell (string labelText, string value, Action<string, string> onTextFieldTextChanged)
    {
        CellLabel.Text = labelText;
        CellTextField.Text = value;
        OnTextFieldTextChanged = onTextFieldTextChanged;

        CellTextField.EditingDidEnd += HandleEditingDidEnd;
    }

    void HandleEditingDidEnd (object sender, EventArgs e)
    {
        var textField = sender as UITextField;
        OnTextFieldTextChanged (CellLabel.Text, textField.Text);
    }

    // clean up
    public override void PrepareForReuse ()
    {
        base.PrepareForReuse ();

        OnTextFieldTextChanged = null;
        CellTextField.EditingDidEnd -= HandleEditingDidEnd;
    }

    protected override void Dispose (bool disposing)
    {
        if (disposing) {
            OnTextFieldTextChanged = null;
        }

        base.Dispose (disposing);

    }

}

The important things here are the SetupCell method and the HandleEditingDidEnd event handler. You hook into the EditingDidEnd of the UITextField so that you can invoke the passed in onTextFieldTextChanged action.

3.) Add a OnTextFieldTextChange handler and Implement the GetCell method in your View Controller like this:

public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
    var cell = tableView.DequeueReusableCell ("CellIdentifier")  as CTextInput ?? new CTextInput ();

    var labelText = DataSource.Keys.ElementAt (indexPath.Row);
    var textFieldText = DataSource.Values.ElementAt (indexPath.Row);

    cell.SetupCell (labelText, textFieldText, OnTextFieldTextChange);

    return cell;
}


public void OnTextFieldTextChange (string key, string value)
{
    if (DataSource.ContainsKey (key)) {
        DataSource [key] = value;
    }
}

Here you define a OnTextFieldTextChange method which can be passed in for the Action<string, string> onTextFieldTextChanged parameter in the SetupCell method that was defined earlier in the CTextInput class.

In OnTextFieldTextChange method all you do is update the value for the given key in your DataSource.

Now when the UITextField emits an EditingDidEnd event, the data source is updated to include the value the user entered.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM