UIActivityIndi​​catorView.StartAnimating重写UIActivityIndi​​catorView.Hidden绑定

时间:2015-01-12 16:19:40

标签: xamarin.ios xamarin mvvmcross

我在Controller.ViewDidLoad

中创建了一个UIActivityIndi​​catorView
UIActivityIndicatorView spinner = new UIActivityIndicatorView();
spinner.StartAnimating();
spinner.Hidden = true;
this.Add(spinner);

然后我将它绑定到MVVMCross

var set = this.CreateBindingSet<TipView, TipViewModel>();
set.Bind(spinner).For(v => v.Hidden).To(vm => vm.IsBusy).WithConversion("Inverse");

当View最初加载时,UIActivityIndi​​catorView正在旋转可见。这是不正确的,因为在ViewModel的Init()中将IsBusy属性显式设置为False。我可以看到这种情况发生,我可以看到转换器反转了值。

我知道绑定已正确连接,因为如果我触发更新IsBusy属性的命令,则会按预期显示和隐藏指示符。这只是初始状态不正确。

StartAnimating 方法似乎会导致隐藏隐藏标志。如果我没有调用StartAnimating指标隐藏并按预期显示。当然这意味着我没有动画 指示器。

我可以获得一个WeakReference到VM,听取PropertyChanged并调用StartAnimating但这看起来有点垃圾。

有没有人有更好的想法?

2 个答案:

答案 0 :(得分:4)

您可以执行以下选项:

  1. 订阅PropertyChanged更改并在事件处理程序中编写自定义代码(正如您在问题中所建议的那样)

  2. 继承自UIActivityIndicatorView并编写一个公共get;set;属性,该属性在Start处理程序中提供复合功能(调用Hiddenset

    public class MyIndicatorView : UIActivityIndicatorView {
          // ctors
    
         private bool _superHidden;
         public bool SuperHidden {
            get { return _supperHidden; }
            set { _superHidden = value; if (!value) StartAnimating() else StopAnimating(); Hidden = value; }
         }
    }
    
  3. 提供View公开get;set;属性并将复合功能放入其中(例如set.Bind(this).For(v => v.MyAdvanced)...

         private bool _myAdvanced;
         public bool MyAdvanced {
            get { return myAdvanced; }
            set { myAdvanced = value; if (!value) _spinner.StartAnimating() else _spinner.StopAnimating(); _spinner.Hidden = value; }
         }
    
  4. 为Hidden编写自定义绑定,它取代了默认功能,并包含组合的StartHidden调用(有关自定义绑定的更多信息,有几个N + 1教程)< / p>

答案 1 :(得分:1)

在阅读@ slodge的回复之后,我沿着Weak Event Listener的道路前进,并在View中将代码运行到Hide and StartAnimating。复制并粘贴了这种方法3次我意识到必须改变,所以我实现了他的第4个建议并写了一个Custom Binding。 FWIW这里是自定义绑定

/// <summary>
/// Custom Binding for UIActivityIndicator Hidden. 
/// This binding will ensure the indicator animates when shown and stops when hidden
/// </summary>
public class ActivityIndicatorViewHiddenTargetBinding : MvxConvertingTargetBinding
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ActivityIndicatorViewHiddenTargetBinding"/> class.
    /// </summary>
    /// <param name="target">The target.</param>
    public ActivityIndicatorViewHiddenTargetBinding(UIActivityIndicatorView target)
        : base(target)
    {
        if (target == null)
        {
            MvxBindingTrace.Trace(
                                MvxTraceLevel.Error,
                                "Error - UIActivityIndicatorView is null in ActivityIndicatorViewHiddenTargetBinding");
        }
    }

    /// <summary>
    /// Gets the default binding mode.
    /// </summary>
    /// <value>
    /// The default mode.
    /// </value>
    public override MvxBindingMode DefaultMode
    {
        get { return MvxBindingMode.OneWay; }
    }

    /// <summary>
    /// Gets the type of the target.
    /// </summary>
    /// <value>
    /// The type of the target.
    /// </value>
    public override System.Type TargetType
    {
        get { return typeof(bool); }
    }

    /// <summary>
    /// Gets the view.
    /// </summary>
    /// <value>
    /// The view.
    /// </value>
    protected UIActivityIndicatorView View
    {
        get { return Target as UIActivityIndicatorView; }
    }

    /// <summary>
    /// Sets the value.
    /// </summary>
    /// <param name="target">The target.</param>
    /// <param name="value">The value.</param>
    protected override void SetValueImpl(object target, object value)
    {
        var view = (UIActivityIndicatorView)target;
        if (view == null)
        {
            return;
        }

        view.Hidden = (bool)value;

        if (view.Hidden)
        {
            view.StopAnimating();
        }
        else
        {
            view.StartAnimating();
        }
    }
}