具有MvvmCross单元重用的Monotouch对话框在滚动时混合单元数据

时间:2014-07-03 07:37:38

标签: ios xamarin.ios mvvmcross monotouch.dialog

我正在使用相当多的子类单触对话框RootElements构建一个应用程序。自定义单元格外观的一部分是根据从视图模型绑定的布尔值在单元格的最右侧添加通知视图,作为该特定单元格验证的一部分。

如果所有单元格永远都不会出现,那么这种方法很有用。但是当滚动发挥作用时,这些添加到细胞中的UIViews变得混杂起来。

我已经尝试重写CellKey getter和各种其他选项无济于事,我们将非常感谢任何帮助。谢谢。

    public class PgpStyledRootElement : RootElement, IElementSizing, IValidatableElement
{
    float _height;

    bool _isRequired = false;

    UIView notificationView;

    protected IMvxMessenger _messenger;

    protected MvxSubscriptionToken _token;

    public WeakReference WeakNotificationView { get; set;}
    public UIView NotificationView
    {
        get
        {
            if (WeakNotificationView == null || !WeakNotificationView.IsAlive)
                return null;
            return WeakNotificationView.Target as UIView;
        }
    }

    private UITableViewCell _activeCell;
    public UITableViewCell ActiveCell
    {
        get 
        {
            if(_activeCell == null)
            {
                _activeCell = this.GetActiveCell ();
            }

            return _activeCell;
        }
        set
        {
            _activeCell = value;
        }
    }

    private bool _isValid = true;
    public bool IsValid 
    {
        get { return _isValid; } 
        set 
        {
            _isValid = value; 

            if (_isValid)
            {
                UIApplication.SharedApplication.InvokeOnMainThread (RemoveNotificationView);
            }
            else 
            {
                UIApplication.SharedApplication.InvokeOnMainThread (AddNotificationView);
            }
        } 
    }

    public PgpStyledRootElement(string caption, bool isRequired, Group group = null) : base(caption, group) {
    }

    public PgpStyledRootElement(string caption, bool isRequired, float height, bool fullPageWidth, Group group = null) : base(caption, group) {
        _height = height;
    }

    public PgpStyledRootElement(string caption, bool isRequired, float height, Group group = null, string defaultDetailText = null) : base(caption, group) {
        _height = height;
        _isRequired = isRequired;
        _messenger = Mvx.Resolve<IMvxMessenger> ();
        _token = _messenger.Subscribe<ScreenWillRotateMessage> (HandleScreenWillRotate);

    }

    public PgpStyledRootElement (string caption, bool isRequired, float height, Func<RootElement, UIViewController> createOnSelected) : base (caption, createOnSelected)
    {
        this.Sections = new List<Section> ();
        _height = height;

        _messenger = Mvx.Resolve<IMvxMessenger> ();
        _token = _messenger.Subscribe<ScreenWillRotateMessage> (HandleScreenWillRotate);
    }

    public PgpStyledRootElement(string caption,  float height, Group group = null) : base(caption, group) {
        _height = height;
    }

    protected override UITableViewCell GetCellImpl (UITableView tv)
    {
        var cell = base.GetCellImpl (tv);

        HandleInitialLoadValidation (cell);

        return cell;
    }

    protected override void UpdateCellDisplay (UITableViewCell cell)
    {
        base.UpdateCellDisplay (cell);

        if (cell != null) {
            cell.TextLabel.TextColor = CaptureListingsStyleConfig.DefaultTableCellTextColor;
            cell.SetNeedsLayout ();
        }
    }

    public void HandleInitialLoadValidation (UITableViewCell cell)
    {
        if (_isRequired) 
        {
            if (!IsValid)
            {
                AddInitialNotificationView (cell);
            }
        }
    }

    static void GetRequiredIndicatorFrame (UITableViewCell cell, out float indicatorPointX, out float indicatorHeight)
    {
        if (UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.Portrait || UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.PortraitUpsideDown) {
            indicatorPointX = cell.Frame.Width + 120;
            indicatorHeight = cell.Frame.Height;
        }
        else {
            indicatorPointX = cell.Frame.Width * 2 + 56;
            indicatorHeight = cell.Frame.Height;
        }
    }

    static void GetRequiredIndicatorFrameForRotationChange (UITableViewCell cell, out float indicatorPointX, out float indicatorHeight)
    {
        if (UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.Portrait || UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.PortraitUpsideDown) {
            indicatorPointX = cell.Frame.Width - 263;
            indicatorHeight = cell.Frame.Height;
        }
        else {
            indicatorPointX = cell.Frame.Width + 249;
            indicatorHeight = cell.Frame.Height;
        }
    }

    void HandleScreenWillRotate (ScreenWillRotateMessage obj)
    {
        RectangleF newFrame;

        if(NotificationView != null)
        {
            const int indicatorpointY = 0;
            const int indicatorWidth = 7;

            float indicatorPointX;
            float indicatorHeight;

            GetRequiredIndicatorFrameForRotationChange (ActiveCell, out indicatorPointX, out indicatorHeight);

            CreateNewNotificationViewFrame (out newFrame, indicatorpointY, indicatorWidth, indicatorPointX, indicatorHeight);

            NotificationView.Frame = newFrame;
        }
    }

    static void CreateNewNotificationViewFrame (out RectangleF newFrame, int indicatorpointY, int indicatorWidth, float indicatorPointX, float indicatorHeight)
    {
        newFrame = new RectangleF (indicatorPointX, indicatorpointY, indicatorWidth, indicatorHeight);
    }

    public void AddInitialNotificationView (UITableViewCell cell) 
    {
        if (cell != null) {

            const int indicatorpointY = 0;
            const int indicatorWidth = 7;

            float indicatorPointX;
            float indicatorHeight;

            GetRequiredIndicatorFrame (cell, out indicatorPointX, out indicatorHeight);

            if (Util.UserInterfaceIdiomIsPhone) {
                indicatorPointX = cell.Frame.Width - indicatorWidth;
            }

            AddViewToCell (cell, indicatorpointY, indicatorWidth, indicatorPointX, indicatorHeight);
        }
    }

    public void AddNotificationView () 
    {
        if (ActiveCell != null) {

            const int indicatorpointY = 0;
            const int indicatorWidth = 7;

            var indicatorPointX = ActiveCell.Frame.Width - indicatorWidth;
            var indicatorHeight = ActiveCell.Frame.Height;

            if (Util.UserInterfaceIdiomIsPhone) {
                indicatorPointX = ActiveCell.Frame.Width - indicatorWidth;
            }

            AddViewToCell (ActiveCell, indicatorpointY, indicatorWidth, indicatorPointX, indicatorHeight);
        }
    }

    void AddViewToCell (UITableViewCell cell, int indicatorpointY, int indicatorWidth, float indicatorPointX, float indicatorHeight)
    {
        if (NotificationView == null) {

            notificationView = new UIView (new RectangleF (indicatorPointX, indicatorpointY, indicatorWidth, indicatorHeight));
            notificationView.BackgroundColor = UIColor.Red;

            WeakNotificationView = new WeakReference (notificationView);
            cell.Add (NotificationView);
        }
    }

    public void RemoveNotificationView()
    {
        if(NotificationView != null)
        {
            NotificationView.RemoveFromSuperview ();
            WeakNotificationView = null; //This should technically not be necessary, but lets do it anyway
        }
    }


    #region IElementSizing implementation

    public float GetHeight (UITableView tableView, NSIndexPath indexPath)
    {
        if(_height == 0.0f)
            return CaptureListingsStyleConfig.DefaultTextCellHeight; //return CaptureListingsStyleConfig.DefaultRootCellHeight ();

        return _height;
    }

    #endregion

}

1 个答案:

答案 0 :(得分:0)

每当需要显示一个单元格时,DialogViewController会调用Element的{​​{1}}方法。然后,此方法执行GetCell,然后执行GetCellImpl

在重用的情况下,我怀疑你的UpdateCellDisplay正在RootElement中返回重用的Cell(因为这是基类返回的内容),然后没有完全更新它。您可以尝试修改GetCellImpl方法,以便更新单元格显示以反映UpdateCellDisplay的当前状态 - 即添加/删除通知显示。