Xamarin Forms ListView Command to VM with EventToCommandBeha



,所以我想在视图模型中使用命令,以便我可以与listView进行交互。我查看了EventTocommandBehavior的示例。我试图在项目中复制代码,但由于某种原因,我无法使其工作。

我得到的是:

shogeti.core.core.behaviors文件夹

内部的行为base.cs
using System;
using Xamarin.Forms;
namespace Sogeti.Core
{
 public class BehaviorBase<T> : Behavior<T> where T : BindableObject
 {
     public T AssociatedObject { get; private set; }
     protected override void OnAttachedTo(T bindable)
     {
         base.OnAttachedTo(bindable);
         AssociatedObject = bindable;
         if (bindable.BindingContext != null)
         {
             BindingContext = bindable.BindingContext;
         }
         bindable.BindingContextChanged += OnBindingContextChanged;
     }
     protected override void OnDetachingFrom(T bindable)
     {
         base.OnDetachingFrom(bindable);
         bindable.BindingContextChanged -= OnBindingContextChanged;
         AssociatedObject = null;
     }
     void OnBindingContextChanged(object sender, EventArgs e)
     {
         OnBindingContextChanged();
     }
     protected override void OnBindingContextChanged()
     {
         base.OnBindingContextChanged();
         BindingContext = AssociatedObject.BindingContext;
     }
 }
} 

eventtocommandbehavior.cs sogeti.core.behaviors文件夹

using System;
using System.Reflection;
using System.Windows.Input;
using Xamarin.Forms;
namespace Sogeti.Core
{
public class EventToCommandBehavior : BehaviorBase<View>
{
    Delegate eventHandler;
    public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
    public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
    public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
    public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
    public string EventName
    {
        get { return (string)GetValue(EventNameProperty); }
        set { SetValue(EventNameProperty, value); }
    }
    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }
    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }
    public IValueConverter Converter
    {
        get { return (IValueConverter)GetValue(InputConverterProperty); }
        set { SetValue(InputConverterProperty, value); }
    }
    protected override void OnAttachedTo(View bindable)
    {
        base.OnAttachedTo(bindable);
        RegisterEvent(EventName);
    }
    protected override void OnDetachingFrom(View bindable)
    {
        DeregisterEvent(EventName);
        base.OnDetachingFrom(bindable);
    }
    void RegisterEvent(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            return;
        }
        EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
        if (eventInfo == null)
        {
            throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
        }
        MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
        eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
        eventInfo.AddEventHandler(AssociatedObject, eventHandler);
    }
    void DeregisterEvent(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            return;
        }
        if (eventHandler == null)
        {
            return;
        }
        EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
        if (eventInfo == null)
        {
            throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
        }
        eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
        eventHandler = null;
    }
    void OnEvent(object sender, object eventArgs)
    {
        if (Command == null)
        {
            return;
        }
        object resolvedParameter;
        if (CommandParameter != null)
        {
            resolvedParameter = CommandParameter;
        }
        else if (Converter != null)
        {
            resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
        }
        else
        {
            resolvedParameter = eventArgs;
        }
        if (Command.CanExecute(resolvedParameter))
        {
            Command.Execute(resolvedParameter);
        }
    }
    static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var behavior = (EventToCommandBehavior)bindable;
        if (behavior.AssociatedObject == null)
        {
            return;
        }
        string oldEventName = (string)oldValue;
        string newEventName = (string)newValue;
        behavior.DeregisterEvent(oldEventName);
        behavior.RegisterEvent(newEventName);
    }
}
}

SogeTi.Core.Core.Converters文件夹

selectedIteMeventArgStoSelectedItemConverter.cs
 using System;
 using System.Globalization;
 using Xamarin.Forms;
 namespace Sogeti.Core
 {
public class SelectedItemEventArgsToSelectedItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var eventArgs = value as SelectedItemChangedEventArgs;
        return eventArgs.SelectedItem;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
}

sogeti.core.core.viewmodel文件夹

using System;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using Xamarin.Forms;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Sogeti.Core
{
public class SogetistDetailsViewModel : SimpleViewModel
{
    private Sogetist sogetist;
    public ICommand ViewSelectedCommand { get; private set; }
    public string FullName
    {
        get
        {
            return sogetist.Name + " " + sogetist.LastName;
        }
    }
    public string Introduction
    {
        get
        {
            return sogetist.Introduction;
        }
        set
        {
            if (sogetist.Introduction != value)
            {
                sogetist.Introduction = value;
                RaisePropertyChanged(() => Introduction);
            }
        }
    }
    public string Function
    {
        get
        {
            return sogetist.Function.Name;
        }
        set
        {
            if (value != sogetist.Function.Name)
            {
                sogetist.Function.Name = value;
                RaisePropertyChanged(() => Function);
            }
        }
    }
    public string Skills
    {
        get
        {
            List<string> skills = sogetist.Skill.Select(x => x.Name).ToList();
            return string.Join(", ", skills);
        }
    }
    public string Image
    {
        get
        {
            return sogetist.Image;
        }
        set
        {
            if (value != sogetist.Image)
            {
                sogetist.Image = value;
                RaisePropertyChanged(() => Image);
            }
        }
    }
    public SogetistDetailsViewModel() : this(new Sogetist())
    {
    }
    public SogetistDetailsViewModel(Sogetist sogetist)
    {
        this.sogetist = sogetist;
        Image = this.sogetist.Image;
        ViewSelectedCommand = new Command<Sogetist>(OnViewSelected);
    }
    void OnViewSelected(Sogetist obj)
    {
        String a = obj.Name;
    }
}
}

mainpage.xaml sogeti命名空间

 <?xml version="1.0" encoding="utf-8" ?>
 <ContentPage x:Class="Sogeti.MainPage"
         xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:core="clr-namespace:Sogeti.Core;assembly=Sogeti.Core"
         Title="Sogetist list">
<ContentPage.Resources>
    <ResourceDictionary>
        <core:SelectedItemEventArgsToSelectedItemConverter x:Key="SelectedItemConverter" />
    </ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="listView"
          CachingStrategy="RecycleElement"
          Footer="{Binding Count}"
          IsPullToRefreshEnabled="True"
          ItemsSource="{Binding .}">
    <ListView.Behaviors>
        <core:EventToCommandBehavior EventName="ItemSelected" Command="{Binding ViewSelectedCommand}" Converter="{StaticResource SelectedItemConverter}" />
    </ListView.Behaviors>
    <ListView.FooterTemplate>
        <DataTemplate>
            <ContentView BackgroundColor="#FF4411" Padding="0,5">
                <Label FontSize="Micro"
                       HorizontalTextAlignment="Center"
                       Text="{Binding .,
                                      StringFormat='{0} Sogetists'}"
                       TextColor="White"
                       VerticalTextAlignment="Center">
                    <Label.Triggers>
                        <DataTrigger Binding="{Binding .}"
                                     TargetType="Label"
                                     Value="1">
                            <Setter Property="Text" Value="{Binding ., StringFormat='{0} Sogetist'}" />
                        </DataTrigger>
                    </Label.Triggers>
                </Label>
            </ContentView>
        </DataTemplate>
    </ListView.FooterTemplate>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ImageCell Detail="{Binding Function}"
                       ImageSource="{Binding Image}"
                       Text="{Binding FullName}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
</ContentPage>

mainpage.xaml.cs

 using Xamarin.Forms;
 using Sogeti.Core;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using System;
 using System.Collections.ObjectModel;
 using System.Linq;
 namespace Sogeti
 {
public partial class MainPage : ContentPage
{
    private readonly BackendlessHandler backendless = new BackendlessHandler();
    public ObservableCollection<SogetistDetailsViewModel> Sogetists { get; private set; }
    public MainPage()
    {
        InitializeComponent();
    }
    protected override async void OnAppearing()
    {
        base.OnAppearing();
        if (Sogetists == null)
        {
            await LoadSogetistsAsync();
            BindingContext = Sogetists;
        }
    }
    private async Task LoadSogetistsAsync()
    {
        IsBusy = true;
        try
        {
            var sogetistDetailsViewModelList = (await backendless.GetAllSogetistsAsync()).OrderBy(x => x.Name).Select(x => new SogetistDetailsViewModel(x));
            Sogetists = new ObservableCollection<SogetistDetailsViewModel>(sogetistDetailsViewModelList);
        }
        catch (Exception ex)
        {
            await this.DisplayAlert("Error", "Failed to download sogetists: " + ex.Message, "OK");
        }
        finally
        {
            IsBusy = false;
        }
    }
}
}

您的问题是您定义的命令的绑定。

MainPage背后没有ViewModel,而是当前您只需在视图本身中写下逻辑即可。我建议使用纯MVVM方法来简化您的解决方案,为此,您需要:

  • 创建MainViewModel
  • 将所有逻辑从MainPage移至MainViewModel
  • MainPageBindingContext设置为MainViewModel

因此,您的MainViewModel将包含ObservalbeCollection< SogetistDetailsViewModel>&amp;您使用SogetistDetailsViewModel参数的命令仅定义一次。

我建议使用此插件。(来源(

您可以在我的github存储库中找到一个示例。

这是xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:TestListViewMultiSelectItems" 
    xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
    x:Class="TestListViewMultiSelectItems.TestListViewMultiSelectItemsPage">
        <ContentPage.Resources>
        <ResourceDictionary>
            <local:SelectedItemEventArgsToSelectedItemConverter x:Key="SelectedItemConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Padding="20,20,20,20">
        <Label Text = "{Binding SelectedItemsCounter, StringFormat='SelectedItems' Counter {0}'}" HorizontalTextAlignment = "Center"/> 
        <ListView ItemsSource="{Binding Items}">
            <ListView.Behaviors>
            <behaviors:EventHandlerBehavior EventName="ItemTapped">
                <behaviors:InvokeCommandAction Command="{Binding ItemTappedCommand}"/>
                </behaviors:EventHandlerBehavior>
            </ListView.Behaviors>
            <ListView.ItemTemplate> 
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <Label Text="{Binding DisplayName}" TextColor = "Fuchsia" HorizontalOptions = "StartAndExpand"/>
                            <BoxView Color="Fuchsia" IsVisible="{Binding Selected}" HorizontalOptions = "End"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

在此示例中,我使用itemtappedCommand。

在我的ViewModel中

    ItemTappedCommand = new Command((object model) => {
        if (model != null && model is ItemTappedEventArgs) {
            if (!((Model)((ItemTappedEventArgs)model).Item).Selected)
                SelectedItemsCounter++;
            else
                SelectedItemsCounter--;
            ((Model)((ItemTappedEventArgs)model).Item).Selected = !((Model)((ItemTappedEventArgs)model).Item).Selected;
        }
    });

最新更新