【问题标题】:MvvmCross Custom Binding not notified by RaisePropertyChangedRaisePropertyChanged 未通知 MvvmCross 自定义绑定
【发布时间】:2017-04-14 19:34:54
【问题描述】:

我正在尝试在 MvxImageView(在 android CardView 内)上实现可触发动画,以便在卡片 ViewModel 上的属性更改时将颜色(绿色或红色)叠加到图像上。我使用 Stuart Lodge 的示例 here 创建了自定义类 DynamicImageView。

public class DynamicImageView : MvxImageView
{
    public DynamicImageView(Context context) : base(context)
    {
    }

    public DynamicImageView(Context context, IAttributeSet attrs) : base(context, attrs)
    {
    }

    public DynamicImageView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
    }

    protected DynamicImageView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        Drawable d = this.Drawable;

        if (d != null)
        {
            // ceil not round - avoid thin vertical gaps along the left/right edges
            int width = MeasureSpec.GetSize(widthMeasureSpec);
            int height = (int)Math.Ceiling(width * (float)d.IntrinsicHeight / d.IntrinsicWidth);
            this.SetMeasuredDimension(width, height);
        }
        else
        {
            base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    private ObjectAnimator colorFilterAnimation;

    private string _animatingColor;
    public string AnimatingColor
    {
        set
        {
            System.Diagnostics.Debug.WriteLine("Animation triggered");
            if (value != _animatingColor)
            {
                _animatingColor = value;
                colorFilterAnimation = ObjectAnimator.OfObject((ImageView)this, "colorFilter", new ArgbEvaluator(), 0, 0);
                switch (value)
                {
                    case "red":
                        colorFilterAnimation.SetObjectValues(0, new Color(100, 0, 0, 80).ToArgb());
                        System.Diagnostics.Debug.WriteLine("Starting Red Animation");
                        break;
                    case "green":
                        colorFilterAnimation.SetObjectValues(0, (int)Color.Green);
                        System.Diagnostics.Debug.WriteLine("Starting Green Animation");
                        break;
                }
                colorFilterAnimation.SetDuration(1000);
                colorFilterAnimation.Start();
            }
        }
    }
}

在此控件的 ViewModel 中,我还定义了匹配属性,遵循标准 MvvmCross 表示法:

private string _animatingColor;
    public string AnimatingColor {
        get
        {
            return _animatingColor;
        }
        set
        {
            _animatingColor = value;
            Debug.WriteLine("AnimatingColor set to " + value);
            RaisePropertyChanged(() => AnimatingColor);
        }
    }

此属性在单击卡片时发生更改,当我单击时,我确实看到属性 set 内的调试打印,但它似乎没有触发控件内的 set AnimatingColor全部。控件在axml中引用正常:

<DynamicImageView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:scaleType="centerCrop"
  local:MvxBind="ImageUrl 'http:'+Profile.Headshot.Url; AnimatingColor .AnimatingColor" />

值得一提的是,imageUrl 确实正确绑定,并在 ViewModel 中更改 Url 时按预期更新。此外,Debug.PrintLine("Animation triggered") 确实会在创建卡片时打印,但不会在 ViewModel 上更改属性时打印。

【问题讨论】:

  • 您是否为AnimatingColor 编写了自定义绑定?如果可以,可以发一下吗?
  • 因为我不知道你这么说是什么意思 - 我希望这可能是我的问题所在。但是,根据 n+1 天的示例,由于我只是为AnimatingColor 使用了一个字符串,我不知道我需要更多的东西来将字符串绑定到添加的属性。编辑:当然,我对这种绑定的工作方式有错误的可能性持非常开放的态度,我只是想确保我提供了尽可能多的信息。
  • local:MvxBind 绑定的属性需要为它们编写一个custom binding 才能执行任何操作。您使用的 ImageUrl 绑定按预期工作的原因是因为在 MvvmCross 本身的某个地方已经为它编写了一个目标绑定。如果您检查您的调试输出窗口,是否有关于 MvvmCross 无法为 AnimatingColor 绑定控件的消息?
  • 这就是让我失望的原因 - 我没有看到任何消息。我将再次运行并通过输出查看,但这也是我的第一个想法。编辑:AnimatingColor 确实没有绑定错误。它似乎可以识别该属性并适当地绑定来自 ViewModel 的字符串。我将尝试实现自定义绑定,看看会发生什么。
  • 已实现但没有变化 - 仍然没有绑定错误,但在按下项目时没有动画。不过,VM 的属性正在发生变化。

标签: c# xamarin data-binding xamarin.android mvvmcross


【解决方案1】:

正如 cmets 建议的那样,我相信您需要为 DynamicImageView 控件创建自定义绑定。应该这样做:

public class DynamicImageViewAnimatingColorBinding : MvxTargetBinding
{
    public DynamicImageViewAnimatingColorBinding(DynamicImageView target) : base(target)
    {
    }

    protected DynamicImageView View => Target as DynamicImageView;

    public override MvxBindingMode DefaultMode => MvxBindingMode.OneWay;

    public override Type TargetType => typeof(string);

    public override void SetValue(object value)
    {
        var view = View;
        if (view == null)
            return;

        view.AnimatingColor = (string) value;
    }
}

然后你需要在你的 Setup 类中注册它以便 MvvmCross 可以使用它:

protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
    {
        registry.RegisterCustomBindingFactory<DynamicImageView>(
            nameof(DynamicImageView.AnimatingColor),
            image => new DynamicImageViewAnimatingColorBinding (image));

        base.FillTargetFactories(registry);
    }

我还没有测试过这段代码,它基于我在 iOS 上使用的一些非常相似的代码,但它在 Android 上应该可以正常工作。希望这会有所帮助。

【讨论】:

  • 已实现但没有变化 - 仍然没有绑定错误,但在按下项目时没有动画。但是,VM 的属性正在发生变化。我会继续修补,看看会发生什么。
  • 可能有点基础,但是页面的 BindingContext 确定设置了吗?
  • 嘿,只是要在这里做一个面部护理,并为浪费您的时间而道歉。我没有提到(阅读:我没有意识到相关性)我的 CardView 被用作 ListView 中的模板这一事实。问题是我没有使用 OvservableCollection,所以属性更改可能没有渗透。我现在可以工作了。感谢你的帮助;您的澄清问题绝对帮助我以更有效的方式检查我的代码以找到潜在问题。干杯!
  • 很高兴我能提供一些帮助:)
  • 我很高兴看到动画现在看起来很棒!现在我想再次尝试使用 RecyclerView。之前的行为很奇怪,但很可能是因为我在那里发现的问题。
【解决方案2】:

James Mundy 的问题让我意识到潜在的问题是我没有在列表中使用 ObservableCollection,因此对底层 ViewModel 的更改没有反映在 UI 中。

【讨论】:

    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    相关资源
    最近更新 更多