所以我想在我的ViewModel中使用命令,这样我就可以与我的listview进行交互。我查看了EventToCommandBehavior的表单示例。我试图复制我的项目中的代码,但由于某种原因,我不能让它工作。
我得到的是:
Sogeti.Core.Behaviors文件夹中的BehaviorBase.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;
}
}
}
Sogeti.Core.Behaviors文件夹中的EventToCommandBehavior.cs
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.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();
}
}
}
MygeModel在Sogeti.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;
}
}
}
Mainge.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;
}
}
}
}
答案 0 :(得分:1)
我建议使用this plugin。 (here the source)
您可以找到示例here, in my GitHub repository。
这是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;
}
});
答案 1 :(得分:1)
您的问题是绑定到您定义的命令。
MainPage
后面没有ViewModel,相反,目前您只是在View本身中编写逻辑。我建议使用纯MVVM方法来简化您的解决方案,为此您需要:
MainViewModel
MainPage
移至MainViewModel
BindingContext
的{{1}}设置为MainPage
因此,您的MainViewModel将包含MainViewModel
&amp;的列表您的命令ObservalbeCollection< SogetistDetailsViewModel>
参数只定义一次。