Bind button click inside customlayout using mvvmcross and mvxlistview

南笙酒味 提交于 2019-12-17 21:32:12

问题


i wanted to bind a button click event inside my customlayout, below is my 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>

below is my ListView layout

<?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>

as you can see above i have called my customlayout inside the listview layout

Below is my 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
    }
}

But i am not able to bind the AcceptCommand command to my button.

i am aware that this will not work because inside my customlayout view i do not get the AcceptCommand command as it is not a part of object MyCustomClass

please help me with some example.

Thanks in advance


回答1:


As you know, data binding works by binding directly to the current ViewModel/Model. You're not able to access properties or commands of the parent view model, unless you provide a property to access the parent.

Anyway, one option is to create a value converter that you use in your binding. This converter will return a MvxCommand object that when executed will use MvxMessenger to publish a message.

The parent view model will subscribe to this message and then execute the command that you want.

I've created a sample based on Stuart Lodge's N=02 example.

https://github.com/kiliman/MvxCommandToMessage

EDIT: I modified the sample to use a generic MessageToCommandValueConverter. You can now pass in the message type in the binding. You still need specific message types though since MvxMessenger.Publish() is global to your app. See the code on GitHub for the changes.


Here's the value converter:

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);
        });
    }
}

And here's how you bind to it in your layout. Use . to pass the current object to the converter.

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

And then finally in your ViewModel, you would subscribe to this message, and call your command:

_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;
    }
}

Hope this helps.



来源:https://stackoverflow.com/questions/23535943/bind-button-click-inside-customlayout-using-mvvmcross-and-mvxlistview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!