MVVMCross可展开列表视图

9
我在想,Mvvmmcross框架中是否存在类似于ExpandableListViews的功能或类似控件,或者这种类型的控件是否可以适用于多平台需求。在http://deapsquatter.blogspot.com/2013/02/mvvmcrossdeapextensions.html找到的功能很棒,但不确定是否可用于展开/折叠功能。
如果有任何指导或示例代码,将不胜感激。

你解决了吗? - Hugo Logmans
2个回答

6
这是关于IT技术的内容(我将它放在Deepsqautter的代码中)。在我整理好代码后,我会将其放在方便的地方,或者它可能是mvvmcross本身的有用补充...
视图:
public class BindableExpandableListView : ExpandableListView
    {
        public BindableExpandableListView(Context context, IAttributeSet attrs)
            : this(context, attrs, new BindableExpandableListAdapter(context))
        {
        }
    public BindableExpandableListView(Context context, IAttributeSet attrs, BindableExpandableListAdapter adapter)
        : base(context, attrs)
    {
        var groupTemplateId = MvxAttributeHelpers.ReadAttributeValue(context, attrs,
                                                                           MvxAndroidBindingResource.Instance
                                                                            .ListViewStylableGroupId,
                                                                           AndroidBindingResource.Instance
                                                                           .BindableListGroupItemTemplateId);
 
        var itemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId(context, attrs);
        SetAdapter(adapter);
        adapter.GroupTemplateId = groupTemplateId;
        adapter.ItemTemplateId = itemTemplateId;
    }

    // An expandableListView has ExpandableListAdapter as propertyname, but Adapter still exists but is always null.
    protected BindableExpandableListAdapter ThisAdapter { get { return ExpandableListAdapter as BindableExpandableListAdapter; } }

    

    private IEnumerable _itemsSource;
    [MvxSetToNullAfterBinding]
    public virtual IEnumerable ItemsSource
    {
        get { return ThisAdapter.ItemsSource; }
        set { ThisAdapter.ItemsSource = value; }
    }

    public int ItemTemplateId
    {
        get { return ThisAdapter.ItemTemplateId; }
        set { ThisAdapter.ItemTemplateId = value; }
    }

    private ICommand _itemClick;
    public new ICommand ItemClick
    {
        get { return _itemClick; }
        set { _itemClick = value; if (_itemClick != null) EnsureItemClickOverloaded(); }
    }

    public ICommand GroupClick { get; set; }

    private bool _itemClickOverloaded = false;
    private void EnsureItemClickOverloaded()
    {
        if (_itemClickOverloaded)
            return;

        _itemClickOverloaded = true;
        base.ChildClick += (sender, args) => ExecuteCommandOnItem(this.ItemClick, args.GroupPosition, args.ChildPosition);
    }


    protected virtual void ExecuteCommandOnItem(ICommand command, int groupPosition, int position)
    {
        if (command == null)
            return;

        var item = ThisAdapter.GetRawItem(groupPosition, position);
        if (item == null)
            return;

        if (!command.CanExecute(item))
            return;

        command.Execute(item);
    }
}

和适配器
public class BindableExpandableListAdapter : MvxAdapter, IExpandableListAdapter
    {
    private IList _itemsSource;

    public BindableExpandableListAdapter(Context context)
        : base(context)
    {
        
    }

    int groupTemplateId;
    public int GroupTemplateId
    {
        get { return groupTemplateId; }
        set
        {
            if (groupTemplateId == value)
                return;
            groupTemplateId = value;

            // since the template has changed then let's force the list to redisplay by firing NotifyDataSetChanged()
            if (ItemsSource != null)
                NotifyDataSetChanged();
        }
    }

    protected override void SetItemsSource(System.Collections.IEnumerable value)
    {
        Mvx.Trace("Setting itemssource");
        if (_itemsSource == value)
            return;
        var existingObservable = _itemsSource as INotifyCollectionChanged;
        if (existingObservable != null)
            existingObservable.CollectionChanged -= OnItemsSourceCollectionChanged;

        _itemsSource = value as IList;

        var newObservable = _itemsSource as INotifyCollectionChanged;
        if (newObservable != null)
            newObservable.CollectionChanged += OnItemsSourceCollectionChanged;

        if (value != null)
        {
            // dit weggehaald FlattenAndSetSource(value);
        }
        else
            base.SetItemsSource(null);
    }



    public int GroupCount { get { return (_itemsSource != null ? _itemsSource.Count : 0); } }
    public void OnGroupExpanded(int groupPosition)
    {
        // do nothing
    }

    public void OnGroupCollapsed(int groupPosition)
    {
        // do nothing
    }

    public bool IsChildSelectable(int groupPosition, int childPosition)
    {
        return true;
    }

    public View GetGroupView(int groupPosition, bool isExpanded, View convertView, ViewGroup parent)
    {
        var item = _itemsSource[groupPosition];
        return base.GetBindableView(convertView, item, GroupTemplateId);
    }

    public long GetGroupId(int groupPosition)
    {
        return groupPosition;
    }

    public Java.Lang.Object GetGroup(int groupPosition)
    {
        return null;
    }

    public long GetCombinedGroupId(long groupId)
    {
        return groupId;
    }

    public long GetCombinedChildId(long groupId, long childId)
    {
        return childId;
    }

    public object GetRawItem(int groupPosition, int position)
    {
        return ((_itemsSource[groupPosition]) as IEnumerable).Cast<object>().ToList()[position];
    }

    public View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
    {
        var sublist = ((_itemsSource[groupPosition]) as IEnumerable).Cast<object>().ToList();

        var item = sublist[childPosition];
        return base.GetBindableView(convertView, item, ItemTemplateId);
    }

    public int GetChildrenCount(int groupPosition)
    {
        return ((_itemsSource[groupPosition]) as IEnumerable).Cast<object>().ToList().Count();
    }

    public long GetChildId(int groupPosition, int childPosition)
    {
        return childPosition;
    }

    public Java.Lang.Object GetChild(int groupPosition, int childPosition)
    {
        return null;
    }

    //public object GetRawItem
}

以下是一个XAML代码示例:

<DeapExtensions.Binding.Droid.Views.BindableExpandableListView
    android:minWidth="25px"
    android:minHeight="25px"
    android:id="@+id/toclist"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="ItemsSource Chapters; ItemClick ShowCommand"
    local:MvxItemTemplate="@layout/indextocsectionlistitem"
    local:GroupItemTemplate="@layout/indextocitem"
    android:background="@android:color/white" />

接下来是一些数据示例(伪代码):

public class SubItem {
  public String Name {get; set;}
}

// this is the special part: a chapter does not CONTAIN a sublist, but IS a list of subitems.
public class Chapter : List<Subitem> {
  public String Name {get; set;}
}

// en some usage code
var chapters = new List<Chapter>();
var chapter = new Chapter(){Name = "chap 1"};
chapter.Add(new SubItem(){Name = " 1"});
chapter.Add(new SubItem(){Name = "item 2"});
chapters.Add(chap);

这是我的MvxBindingAttributes.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="MvxBinding">
    <attr name="MvxBind" format="string"/>
    <attr name="MvxLang" format="string"/>
  </declare-styleable>
  <declare-styleable name="MvxControl">
    <attr name="MvxTemplate" format="string"/>
  </declare-styleable>
  <declare-styleable name="MvxListView">
    <attr name="MvxItemTemplate" format="string"/>
    <attr name="MvxDropDownItemTemplate" format="string"/>
    <attr name="GroupItemTemplate" format="string"/>

  </declare-styleable>
  <item type="id" name="MvxBindingTagUnique"/>
  <declare-styleable name="MvxImageView">
    <attr name="MvxSource" format="string"/>
  </declare-styleable>
</resources>

顺便说一下:我在MvvmCross中只剩下一个项目了,其余的已经转换为Xamarin.Forms甚至远离Xamarin。所以代码不再更新。


1
我已经将代码添加到了一个分支中:https://github.com/hlogmans/MvvmCross.DeapExtensions.git - Hugo Logmans
Hugo,这段代码还能用吗?我升级了MvvmCross 3.0.14并编译了代码。我在我的项目中只引用了dll,但是我无法使用它。你在github上有示例项目吗? - Mario Duarte
好的,它可以工作,但我没有示例项目。你有什么问题? - Hugo Logmans
1
那么你可能还没有编辑过你项目中的mvxbindingattributes.xml文件。在'MvxItemTemplate'所在的同一级别上添加一个'GroupItemTemplate'行。 - Hugo Logmans
现在它已经运行了!我创建了一个名为“DeapExtensionsPluginBootstrap”的类来调用你的PluginLoader。非常感谢你! - Mario Duarte
显示剩余9条评论

1
据我所知,以前没有人做过这件事。
但是你可以将现有的Android控件简单地转换为绑定控件-你已经看到了@deapsquatter的repo中的具体操作步骤。
要转换ExpandableListView,您需要逐步进行以下操作:
1.首先按照您想要使用的结构获取数据
2.然后手工制作一个非绑定UI-只是快速原型设计
3.最后采用@deapsquatter的示例,尝试应用相同的原则。
如果遇到特定问题,您总可以回到这里询问。但是,通过先完成1和2,您将拥有可靠的东西来咨询。
希望这可以帮助到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接