【问题标题】:Does MVVMCross have a way to change the selector when clicking ImageButton on ListView?单击 ListView 上的 ImageButton 时,MVVMCross 是否可以更改选择器?
【发布时间】:2012-10-05 02:01:03
【问题描述】:

问题和不用MVVMCross编程是一样的,不过不知道有没有“跨平台”的解决方案:

当在 MvxBindableListView(或 ListView)上使用 ImageButton 时,我们必须放置一些选项才能在此按钮上使用操作:

        <ImageButton
            ...
            android:focusable="false"
            android:clickable="true" 
            ...
            local:MvxBind="'Click':{'Path':'Command1'}}"
          />

使用这些参数,按钮会对“Command1”做出反应。 但问题是ListView的“视觉选择器”并没有改变。

举个例子:

当您的 ListView 中有 5 行时,第一行被选中。我触摸第 3 行的 ImageButton,“Command1”会做出反应(与 ListView 的第 3 项),但选择器将停留在第一行。

所以,在 Android 中,我们必须这样写一些代码:

_imagebutton.Click += (object sender, EventArgs eventsArgs) =>
    {
        View v = ...
        MvxBindableListView l = ...
        int p = l.GetPositionForView(...);
        l.PerformItemClick(..., p, p); 
     };

使用这段代码,选择了正确的项目并且行为正确(只要我不想使用 ItemClick 触发真实事件)。但这个解决方案是“Android 方式”而不是真正的跨平台(我让你想象一下初始化所有这些东西的可怕代码)

有人有更好的解决方案吗?

雨果

【问题讨论】:

    标签: android listview xamarin.android selector mvvmcross


    【解决方案1】:

    在某种程度上,这感觉就像是“UI 吸引眼球”——因此属于“视图关注点”的范畴——因此 mvvmcross 通常不会尝试跨平台。

    但是……我认为有办法。

    如果 ViewModel 中的命令处理程序也在 ViewModel 上设置了 CurrentSelectedPosition 整数,则每个 UI 都可以将 ViewModel 中的 SelectedItemPosition 绑定到每个 ui 中的每个列表 - 这应该会导致 UI 本地更新选择。

    我认为这会起作用......但在 Android 上它需要一些绑定:

    public class MvxAdapterViewSelectedItemPositionTargetB-inging : MvxBaseAndroidTargetBinding
    {
        private readonly AdapterView _adapterView;
    
        public MvxAdapterViewSelectedItemPositionTargetBinging(AdapterView adapterView)
        {
            _adapterView = adapterView;
            _adapterView.ItemSelected += AdapterViewOnItemSelected;
        }
    
        public override void SetValue(object value)
        {
            _adapterView.SetSelection((int)value);
        }
    
        private void AdapterViewOnItemSelected(object sender, AdapterView.ItemSelectedEventArgs itemSelectedEventArgs)
        {
            FireValueChanged(itemSelectedEventArgs.Position);
        }
    
        public override MvxBindingMode DefaultMode
        {
            get
            {
                return MvxBindingMode.TwoWay;
            }
        }
    
        public override Type TargetType
        {
            get
            {
                return typeof(Int32);
            }
        }
    
        protected override void Dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                if (_adapterView != null)
                {
                    _adapterView.ItemSelected -= AdapterViewOnItemSelected;
                }
            }
            base.Dispose(isDisposing);
        }
    }
    

    注册使用:

            registry.RegisterFactory(new MvxCustomBindingFactory<AdapterView>("SelectedItemPosition", adapterView => new MvxAdapterViewSelectedItemPositionTargetBinging(adapterView)));
    

    并绑定到 axml 中的 UI,例如如:

    <Mvx.MvxBindableListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        local:MvxBind="{'ItemsSource':{'Path':'Emails'},'SelectedItemPosition':{'Path':'CurrentSelectedPosition'}}"
        local:MvxItemTemplate="@layout/listitem_email"
    />
    

    我使用 ViewModel 列表项所在的电子邮件列表测试了这个想法:

        public class SimpleEmail
        {
            public EmailViewModel Parent { get; set; }
            public string From { get; set; }    
            public string Header { get; set; }    
            public string Message { get; set; }    
            public ICommand Command1
            {
                get
                {
                    return new MvxRelayCommand(() => Parent.CurrentSelectedPosition = Parent.Emails.IndexOf(this));
                }
            }
        }
    
    • 但显然这只是一个演示......

    注意:我在上面的代码中使用的是选定的位置而不是选定的对象——因为我知道你使用的列表很长!


    如果您想为您的纯 android 代码考虑一种不同的方法,那么我认为您可以通过从 Mvx.MvxBindableListView (也可能是列表项)继承并使用这些类来更新选择不那么痛苦的方式。

    【讨论】:

    • 嗨斯图尔特,再次感谢您的快速答复。似乎 Android 对 _adapterView.SetSelection((int)value) 没有反应。这就是为什么我必须在 ListView 上以正确的位置执行 PeformItemClick。不过,您的解决方案更漂亮,因为它本机链接在 ListView 上。只要有时间,我会尝试从 MvxBindableListView 继承(截止日期快到了!)
    • AdapterView 似乎在此处响应 SetSelection - 但可能取决于您的“视觉选择器”是什么。我认为 state_selected 和 state_pressed 之间是有区别的——但我不是这方面的专家!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 2019-03-17
    相关资源
    最近更新 更多