-1

I'm creating a checklist in a iOS view inside my Xamarin MvvmCross project. Everything works fine except showing a checkmark when an item is selected and removing the checkmark when an item is deselected.

Inside ViewDidLoad of my controller:

var source = new EntryTypesTableSource(eventsDialogTable, EntryTypeCell.Key, EntryTypeCell.Key);
eventsDialogTable.Source = source;
var set = this.CreateBindingSet<EventsDialogView,EventsDialogViewModel>();
set.Bind(source).To(vm => vm.SelectedItem.EntryTypes);
set.Apply();

I tried calling ReloadData but the data is not changed, only UI is changed, also I tried setting checkmark in GetCell but same problem as inside RowSelected

And code for table source:

public class EntryTypesTableSource : MvxSimpleTableViewSource
{       

    NSIndexPath selectedBefore;      

    public EntryTypesTableSource(UITableView tableView, string nibName, string cellIdentifier = null, NSBundle bundle = null) : base(tableView, nibName, cellIdentifier, bundle)
    {
        tableView.AllowsMultipleSelection = false;
        tableView.AllowsSelection = true;

    }


    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        UITableViewCell cell = base.GetCell(tableView, indexPath);  
        //Default first item is selected            
        if (indexPath.Row == 0 )
            {
                cell.Accessory = UITableViewCellAccessory.Checkmark;
                selectedBefore = indexPath;
            }


        return cell;           

    }


    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        base.RowSelected(tableView, indexPath);



        if (indexPath != null)
        {

            UITableViewCell cellNow = tableView.CellAt(indexPath);//currently selected
            UITableViewCell cellOld = tableView.CellAt(selectedBefore); //previous                     



            if (selectedBefore != indexPath)
            {

                cellOld.Accessory = UITableViewCellAccessory.None;
                tableView.DeselectRow(selectedBefore, true);

                cellNow.Accessory = UITableViewCellAccessory.Checkmark;
                selectedBefore = indexPath;

                tableView.EndUpdates();


            }

        }          

    }


}

Controller code:

 public partial class EventsDialogView : MvxViewController<EventsDialogViewModel>
    {


        public EventsDialogView()
        {           

        }

        public override void ViewDidLoad()
        {
            // Releases the view if it doesn't have a superview.

            base.ViewDidLoad();

             //values
            var dialogWidth = 0.8 * this.View.Frame.Width;
            //float headerHeight = 50f;
            //float footerHeight = 50f;
            float rowHeight = 50f;
            int numberOfRows = selectedItem.EntryTypes.Count + 2;//+2 for header and footer
            float tableHeigth = numberOfRows * rowHeight;

            //table
            var eventsDialogTable = new UITableView();
            eventsDialogTable.Frame = new CoreGraphics.CGRect((this.View.Frame.Width - dialogWidth) / 2, (this.View.Frame.Height - tableHeigth) / 2, dialogWidth, tableHeigth);
            this.View.AddSubview(eventsDialogTable);

            var source = new EntryTypesTableSource(eventsDialogTable);
            eventsDialogTable.Source = source;        

            eventsDialogTable.SeparatorStyle = UITableViewCellSeparatorStyle.None;

            /*Binding*/
            var set = this.CreateBindingSet<EventsDialogView,EventsDialogViewModel>();            
            set.Bind(source).To(vm => vm.SelectedItem.EntryTypes);
            set.Bind(source).For(s => s.SelectionChangedCommand).To(vm => vm.EntrySelected);      
            set.Apply();          

        }  


    }

ViewModel:

public class EventsDialogViewModel : MvxViewModel
{
      private ObservableCollection<EntryType> entryTypeCollection = new ObservableCollection<EntryType>();
        private Device selectedItem;

    private EntryType selectedEntry;
      public EventsDialogViewModel(){}
       public ObservableCollection<EntryType>EntryTypeCollection
    {
        get { return entryTypeCollection; }
        set
        {
            entryTypeCollection = value;
            RaisePropertyChanged(() => EntryTypeCollection);
        }
    }

      public Device SelectedItem
    {
        get { return selectedItem; }
        set
        {
            selectedItem = value;
            RaisePropertyChanged(() => SelectedItem);
        }
    }

    public EntryType SelectedEntry
    {
        get { return selectedEntry; }
        set
        {
            selectedEntry = value;
            RaisePropertyChanged(() => SelectedEntry);
        }
    }

}

Binding works fine, and I can catch clicked/selected item, but view is not updating (I use xcode simulator). Any suggestion is welcome!

iki93
  • 21
  • 6

2 Answers2

0

You could try to swap your TableSource code with this:

public class EntryTypesTableSource : MvxTableViewSource
{
    private bool _isFirst = true;
    private NSIndexPath _previousSelectedRow = null;

    public HomeTableViewSource(UITableView tableView) : base(tableView)
    {
        tableView.RegisterNibForCellReuse(EntryTypeCell.Nib, EntryTypeCell.Key);

        tableView.AllowsMultipleSelection = false;
        tableView.AllowsSelection = true;
    }

    protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
    {
        var cell = tableView.DequeueReusableCell(EntryTypeCell.Key, indexPath);

        if (_isFirst)
        {
            cell.Accessory = UITableViewCellAccessory.Checkmark;
            _previousSelectedRow = indexPath;
            _isFirst = false;
        }

        return cell;
    }

    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        if (_previousSelectedRow == indexPath)
            return;

        base.RowSelected(tableView, indexPath);

        var cell = tableView.CellAt(indexPath);
        cell.Accessory = UITableViewCellAccessory.Checkmark;
        var previousSelectedCell = tableView.CellAt(_previousSelectedRow);
        previousSelectedCell.Accessory = UITableViewCellAccessory.None;

        _previousSelectedRow = indexPath;
    }
}

Then in your view controller you should update

var source = new EntryTypesTableSource(eventsDialogTable, EntryTypeCell.Key, EntryTypeCell.Key);

into

var source = new EntryTypesTableSource(eventsDialogTable);

One thing you could also try is updating your RowSelected method to:

public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
    if (_previousSelectedRow == indexPath)
        return;

    base.RowSelected(tableView, indexPath);

    var cell = tableView.CellAt(indexPath);
    var previousSelectedCell = tableView.CellAt(_previousSelectedRow);

    InvokeOnMainThread(() =>
    {
        cell.Accessory = UITableViewCellAccessory.Checkmark;
        previousSelectedCell.Accessory = UITableViewCellAccessory.None;
    });

    _previousSelectedRow = indexPath;
}
JKL
  • 978
  • 7
  • 21
  • Problem is still there. Actually, when I do table swipe then checkmark show up on the right place. Could it be problem with iPhone simulator because I'm using mac virtual machine for code compile and simulator? – iki93 Jan 16 '19 at 08:18
  • Nah, I'm using the same thing. Can you add the code of your view controller? – JKL Jan 16 '19 at 08:20
  • Check my edit. I'm not sure what can be problem, I tried to do some kind of refresh view but wasn't successfully. – iki93 Jan 16 '19 at 08:42
  • Do you actually see rows in your table? Because I don't see you binding the `ItemsSource` property of your `EntryTypesTableSource` to anything. You should have something like `set.Bind(source).For(x => x.ItemsSource).To(vm => vm.ListProperty);` in your view controller. Where `ListProperty` is a list of items in your ViewModel which represents the items that you want to display as rows. – JKL Jan 16 '19 at 08:53
  • Yes, I can see rows. Here is binding: `set.Bind(source).To(vm => vm.SelectedItem.EntryTypes);` – iki93 Jan 16 '19 at 08:54
  • I'm sorry you're right :) Could you set a breakpoint inside of `RowSelected` and see if it hits when you click a row? – JKL Jan 16 '19 at 08:59
  • Yes, `RowSelected` is called on right way, logic is fine, also I can get selected data in my binding logic and it's always right selected value. Only view is seems like need refresh or checkmark update is delay – iki93 Jan 16 '19 at 09:07
  • Over here the checkmark shows up with a little delay after I click a row. Is not it showing up at all over there in your project or also with a delay? – JKL Jan 16 '19 at 09:09
  • First checkmark show up fine. After that on row click nothing showing, but when I do table swipe it show on . So it seems like delay. I hope so you understand – iki93 Jan 16 '19 at 09:12
  • Could you try invoking the checkmark update on your main thread? See my updated answer (bottom part) – JKL Jan 16 '19 at 09:57
  • Good idea, but still the same :( – iki93 Jan 16 '19 at 10:07
  • I don't completely understand what you mean by 'when I do table swipe'? Do you mean swiping a single row from left to right or something? – JKL Jan 16 '19 at 10:22
  • Maybe swipe isn't right word, actually when I pull down table, like refresh (on this gesture nothing is implemented). – iki93 Jan 16 '19 at 10:29
  • Can you provide your ViewModel? I can't reproduce the issue here.. – JKL Jan 16 '19 at 10:49
  • I'm calling this view controller from another with `this.PresentViewController(dialogView, true, null);` where `dialogView ` is this problematic table view. Could it be problem? I just don't have more ideas, but I thing this is view problem not controller or view model – iki93 Jan 16 '19 at 11:13
  • That could very well be the problem.. I use a custom view presenter to show dialogs. You could create a very simple app which reproduces this behaviour and upload it to github so I can check it out.. – JKL Jan 16 '19 at 11:47
  • I'm sorry for late answer, here is link to project https://drive.google.com/open?id=1GPcxU1Gdt6f6Lt0tK8YzQc8m2SOzN3lI. Thanks for help – iki93 Jan 18 '19 at 13:46
  • I think that presenter is not problem, because when I create table view and display it first with ShowViewModel, same problem is presented – iki93 Jan 23 '19 at 13:48
  • You're doing some spooky things in your views. I would suggest showing your dialog view with `ShowViewModel<>()` instead of triggering an event from your ViewModal. I can't get my hands on a iOS build server at this moment so I'm unable to run and test if this actually works but I uploaded a repository here https://github.com/JGKL/SampleApp with some refactoring of your example. Let me know how this runs so we can hopefully pinpoint what causes the behaviour. – JKL Jan 23 '19 at 18:59
0

After I run app on device everything works fine. It was simulator problem. I kept original version of my code. Thanks everyone for help and time

iki93
  • 21
  • 6