【问题标题】:MVVMCross Custom Control and BindingMVVMCross 自定义控件和绑定
【发布时间】:2015-03-11 17:16:02
【问题描述】:

我创建了一个自定义控件 (CustomCard),它是 CardView 控件的子类。我想在我的项目中的不同地方使用这个控件。

例如,我可以手动将 CustomCard 放置在 xml 布局中,或者我可能希望 CustomCard 成为 MvxListView 中的一个项目。关键是我想尽可能地重用代码并从对 CustomCard 类的控制中受益。

当 CustomCard 被实例化时,我正在使用标准布局充气器充气它的布局,请参见代码:

using System;
using Android.Animation;
using Android.Content;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
using Android.Widget;
public class Card : CardView
{

    private readonly Context _context;

    public Card(Context context)
        : base(context)
    {
        _context = context;
        Init();
    }

    public Card(Context context, IAttributeSet attrs)
        : base(context, attrs)
    {
        _context = context;
        Init();
    }

    private void Init()
    {
        var inflater = (LayoutInflater) _context.GetSystemService(Context.LayoutInflaterService);
        CardView = inflater.Inflate(Resource.Layout.base_card, this);
    }
}

在布局 base_card.xml 中,我有一些我想使用 MVVMCross 绑定的元素,例如,

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white">
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:local="http://schemas.android.com/apk/res-auto"
  android:id="@+id/basecard_title"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
    <!-- Title Text-->
    <TextView
    android:id="@+id/tv_basecard_header_title"
    style="@style/card.title"
    android:text="title text"
    local:MvxBind="Text Title"
    />
    <!-- ImageView -->
    <MvxImageView
    android:id="@+id/ib_basecard_header_button_expand"
    style="@style/card.image"
    local:MvxBind="Bitmap ImageBytes,Converter=InMemoryImage"/>
  </RelativeLayout>
</FrameLayout>

我的实际 base_card 布局要复杂得多。

如果我尝试在另一个 XML 布局中使用我的 CustomCard,则不会发生任何绑定。我认为这是因为我使用标准布局充气器在 CustomCard 中充气我的 base_card 而不是 BindingInflate() 但我不能确定。

我在 SO 和论坛上进行了搜索,但我找不到任何对使用自定义控件的任何人的引用,该自定义控件在使用 MVVMCross 绑定实例化时会膨胀它自己的视图。

有人做过吗,还是我在尝试做一些不可能的事情?

【问题讨论】:

标签: xamarin xamarin.android mvvmcross


【解决方案1】:

我遇到了与 CardView 控件类似的问题。由于 CardView 直接继承自 FrameLayout 我决定使用与 MvxFrameControl 几乎相同的实现(感谢 Stuart 指出 MvxFrameControl 示例):

public class MvxCardView : CardView, IMvxBindingContextOwner
    {
        private object _cachedDataContext;
        private bool _isAttachedToWindow;
        private readonly int _templateId;
        private readonly IMvxAndroidBindingContext _bindingContext;

        public MvxCardView(Context context, IAttributeSet attrs)
            : this(MvxAttributeHelpers.ReadTemplateId(context, attrs), context, attrs)
        {
        }

        public MvxCardView(int templateId, Context context, IAttributeSet attrs)
            : base(context, attrs)
        {
            _templateId = templateId;

            if (!(context is IMvxLayoutInflater))
            {
                throw Mvx.Exception("The owning Context for a MvxCardView must implement LayoutInflater");
            }

            _bindingContext = new MvxAndroidBindingContext(context, (IMvxLayoutInflater)context);
            this.DelayBind(() =>
            {
                if (Content == null && _templateId != 0)
                {
                    Mvx.Trace("DataContext is {0}", DataContext == null ? "Null" : DataContext.ToString());
                    Content = _bindingContext.BindingInflate(_templateId, this);
                }
            });
        }


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

        protected IMvxAndroidBindingContext AndroidBindingContext
        {
            get { return _bindingContext; }
        }

        public IMvxBindingContext BindingContext
        {
            get { return _bindingContext; }
            set { throw new NotImplementedException("BindingContext is readonly in the list item"); }
        }

        protected View Content { get; set; }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.ClearAllBindings();
                _cachedDataContext = null;
            }

            base.Dispose(disposing);
        }

        protected override void OnAttachedToWindow()
        {
            base.OnAttachedToWindow();
            _isAttachedToWindow = true;
            if (_cachedDataContext != null
                && DataContext == null)
            {
                DataContext = _cachedDataContext;
            }
        }

        protected override void OnDetachedFromWindow()
        {
            _cachedDataContext = DataContext;
            DataContext = null;
            base.OnDetachedFromWindow();
            _isAttachedToWindow = false;
        }

        [MvxSetToNullAfterBinding]
        public object DataContext
        {
            get { return _bindingContext.DataContext; }
            set
            {
                if (_isAttachedToWindow)
                {
                    _bindingContext.DataContext = value;
                }
                else
                {
                    _cachedDataContext = value;
                    if (_bindingContext.DataContext != null)
                    {
                        _bindingContext.DataContext = null;
                    }
                }
            }
        }
    }

用法:

<YourNamespace.MvxCardView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    local:MvxTemplate="@layout/base_card"
    local:MvxBind="DataContext ." />

注意:使用自定义实现还解决了我使用 local:MvxBind="Click MyCommand" 将点击命令绑定到 CardView 控件的问题,直到子类化 CardView 才有效。

【讨论】:

  • 伟大的实施!我自己也开始走同样的路,但最终没时间了。谢谢。
猜你喜欢
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-11
相关资源
最近更新 更多