首页 文章

MVVMCross自定义控件和绑定

提问于
浏览
1

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

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

在实例化CustomCard时,我使用标准布局inflater对其布局进行充气,请参阅代码:

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,则不会发生任何绑定 . 我认为这是因为我使用标准布局inflater来扩展我的CustomCard中的base_card而不是BindingInflate(),但我不能确定 .

我已经搜索了SO并通过论坛但是我找不到任何使用自定义控件的人的引用,当使用MVVMCross绑定实例化时,它会膨胀它自己的视图 .

有没有人做过,或者我想做一些不可能的事情?

1 回答

  • 8

    我遇到了与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" 将Click命令绑定到CardView控件,这在继承CardView之前无效 .

相关问题