2017-05-05 35 views
-1

所以我想在我的ViewModel中使用命令,這樣我就可以與我的列表視圖進行交互。我查看了EventToCommandBehavior的窗體示例。我試圖複製我的項目中的代碼,但由於某種原因,我無法讓它工作。Xamarin通過EventToCommandBehavior向虛擬機顯示ListView命令

我得到的是這樣的: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; 
    } 
} 
} 

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

SelectedItemEventArgsToSelectedItemConverter內。 cs裏面Sogeti.Core.Converters文件夾

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

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

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; 
     } 
    } 
} 
} 
+0

這是很多代碼。如果您提供了實際問題,描述了您已經嘗試的內容,期望的結果是什麼以及實際結果如何,那將更容易。 – Krumelur

回答

1

你的問題是結合命令你定義。

您的MainPage後面沒有ViewModel,相反,目前您只需在View中編寫邏輯。我會建議使用純MVVM方法,以簡化您的解決方案,爲此,你需要:

  • 創建MainViewModel
  • 全部移動從MainPageMainViewModel
  • 邏輯設置的BindingContextMainPageMainViewModel

所以你MainViewModel將包含ObservalbeCollection< SogetistDetailsViewModel> &您的命令與0123名單參數只定義一次。

0

我建議使用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; 
     } 
    });