使用mvvmcross和mvxlistview在customlayout中单击绑定按钮

时间:2014-05-08 07:56:38

标签: android android-listview xamarin.android mvvmcross

我想在我的customlayout中绑定一个按钮点击事件,下面是我的customlayout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="63dp">
    <LinearLayout
        android:orientation="horizontal"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <Button
            android:text="Accept"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/acceptBtnOnList"
            android:background="@color/green_color"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textStyle="bold"
            android:layout_weight="1"
            android:textColor="@android:color/background_light"
            local:MvxBind="Click AcceptCommand" />
    </LinearLayout>
</RelativeLayout>
下面的

是我的ListView布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/background_light">
    <Mvx.MvxListView
        android:id="@+id/ListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#FFDAFF7F"
        local:MvxBind="ItemsSource MyList; ItemClick ShowDetailCommand"
        local:MvxItemTemplate="@layout/customlayout" />
</LinearLayout>

如上所示,我在listview布局中调用了我的customlayout

以下是我的ViewModelClass

public class ListViewModel : BaseViewModel
    {
    public IListService ListService { get; set; }

    private MvxCommand _acceptCommand;
    private ListAcceptedResult _accepted;
    private MvxCommand _detailsCommand;        
    private ObservableCollection<MyCustomClass> _myList = new ObservableCollection<MyCustomClass>();

    public ListViewModel(IListService listService)
    {
        ListService = listService;

    }
    public ObservableCollection<MyCustomClass> MyList
    {
        get { return _myList; }
        set
        {
            _myList = value;
            RaisePropertyChanged(() => MyList);
        }
    }

    public ListAcceptedResult Accepted
    {
        get { return _accepted; }
        set
        {
            _accepted = value;
            RaisePropertyChanged(() => Accepted);
            Update();
        }
    }             

    public ICommand AcceptCommand
    {
        get
        {
            IsLoading = true;
            return
                new MvxCommand<MyCustomClass>(
                    item =>
                        //On Success assigning the returned value from service to Accepted Property,
                            error => { IsLoading = false; ReportError(error.Message); }));
        }
    }       



    public async System.Threading.Tasks.Task Update()
    {
        //update logic
    }
}

但是我无法将AcceptCommand命令绑定到我的按钮。

我知道这不起作用,因为在我的customlayout视图中我没有得到AcceptCommand命令,因为它不是对象的一部分MyCustomClass

请帮我举一些例子。

提前致谢

1 个答案:

答案 0 :(得分:0)

如您所知,数据绑定通过直接绑定到当前ViewModel / Model来工作。除非您提供访问父项的属性,否则您无法访问父视图模型的属性或命令。

无论如何,一个选项是创建一个在绑定中使用的值转换器。此转换器将返回MvxCommand对象,该对象在执行时将使用MvxMessenger发布消息。

父视图模型将订阅此消息,然后执行所需的命令。

我根据Stuart Lodge的N = 02示例创建了一个示例。

https://github.com/kiliman/MvxCommandToMessage

编辑:我修改了示例以使用通用MessageToCommandValueConverter。您现在可以在绑定中传递消息类型。您仍然需要特定的消息类型,因为MvxMessenger.Publish()是您应用的全局消息。请参阅GitHub上的代码了解更改。


这是值转换器:

public class KittenAcceptedMessageValueConverter : MvxValueConverter<Kitten, ICommand>
{
    protected override ICommand Convert(Kitten kitten, Type targetType, object parameter, CultureInfo culture)
    {
        return new MvxCommand(() =>
        {
            var messenger = Mvx.Resolve<IMvxMessenger>();
            var message = new KittenAcceptedMessage(this, kitten);
            messenger.Publish(message);
        });
    }
}

以下是您在布局中绑定它的方式。使用.将当前对象传递给转换器。

<Mvx.MvxImageView
    android:layout_width="75dp"
    android:layout_height="75dp"
    android:layout_margin="10dp"
    local:MvxBind="ImageUrl ImageUrl; Click KittenAcceptedMessage(.)" />

最后在ViewModel中,您将订阅此消息,并调用您的命令:

_messenger.Subscribe<KittenAcceptedMessage>(message => 
{
     KittenAcceptedCommand.Execute(message.Kitten); 
});

private MvxCommand<Kitten> _kittenAcceptedCommand;
public ICommand KittenAcceptedCommand
{
    get
    {
        _kittenAcceptedCommand = _kittenAcceptedCommand ?? new MvxCommand<Kitten>(kitten =>
        {
            var toast = Mvx.Resolve<IToastPlugin>();
            toast.Show(string.Format("You accepted {0}", kitten.Name));
        });
        return _kittenAcceptedCommand;
    }
}

希望这有帮助。