MultiSelectable ListView - 未调用ItemSelected

时间:2017-03-20 15:40:20

标签: c# android xamarin uwp xamarin.forms

我创建了一个简单的MultiSelectListView,如下所示,但不知何故ItemSelected事件未被触发。

有人可以告诉我,有什么问题,因为我认为我已经尝试了一切吗?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Xamarin.Forms;

namespace <myProject>.Views
{
   class MultiSelectListView<T> : ContentView
   {
      private ListView _lstView;
      private IEnumerable<WrappedSelection<T>> _wrappedItems;

      public IEnumerable<T> Items
      {
         get { return _wrappedItems?.Select(i => i.Item) ?? new T[0]; }
         set
         {
            _wrappedItems = value?.Select(item => new WrappedSelection<T> { Item = item });
            _lstView.ItemsSource = _wrappedItems;
         }
      }

      public MultiSelectListView(string bindingProperty, IEnumerable<T> items = null)
      {
         if (string.IsNullOrWhiteSpace(bindingProperty))
            throw new ArgumentNullException(nameof(bindingProperty));

         WrappedItemSelectionTemplate.BindingProperty = bindingProperty;

         Content = _lstView = new ListView(ListViewCachingStrategy.RecycleElement)
         {
            ItemTemplate = new DataTemplate(typeof(WrappedItemSelectionTemplate))
         };

         _lstView.ItemSelected += (sndr, e) =>
         {
            if (e.SelectedItem == null)
               return;

            var wrappedSelection = e.SelectedItem as WrappedSelection<T>;
            if (wrappedSelection != null)
               wrappedSelection.IsSelected = !wrappedSelection.IsSelected;

            var lstView = sndr as ListView;
            if (lstView != null)
               lstView.SelectedItem = null;
         };

         Items = items;
      }
   }

   class WrappedItemSelectionTemplate : ViewCell
   {
      public static string BindingProperty { get; internal set; }

      public WrappedItemSelectionTemplate()
      {
         var name = new Label { LineBreakMode = LineBreakMode.WordWrap, Style = Styles.GetTextStyle() };
         name.SetBinding(Label.TextProperty, new Binding($"Item{(!string.IsNullOrEmpty(BindingProperty) ? $".{BindingProperty}" : "")}"));

         var grid = new Grid
         {
            Children = { name },
            ColumnDefinitions = { new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } }
         };

         View = grid;
      }
   }

   class WrappedSelection<T> : INotifyPropertyChanged
   {
      private bool _isSelected;

      public event PropertyChangedEventHandler PropertyChanged = delegate { };

      public bool IsSelected
      {
         get { return _isSelected; }
         set
         {
            if (_isSelected != value)
            {
               _isSelected = value;
               PropertyChanged(this, new PropertyChangedEventArgs(nameof(IsSelected)));
            }
         }
      }

      public T Item { get; set; }
   }
}

1 个答案:

答案 0 :(得分:2)

  

我创建了一个简单的MultiSelectListView,如下所示,但不会以某种方式触发ItemSelected事件。

我已经测试了您的代码并重现了您的问题。我通过将_wrappedItems的类型转换为List<>类型来解决该问题。

MultiSelectListView内部修改代码,如下所示:

public IEnumerable<T> Items
{
      get { return _wrappedItems?.Select(i => i.Item) ?? new T[0]; }
      set
      {
         _wrappedItems = value?.Select(item => new WrappedSelection<T> { Item = item }).ToList();
         _lstView.ItemsSource = _wrappedItems;
      }
}

ListView.SelectedItem更改时,将触发ItemSelected事件。但是当使用从IEnumerable返回的Linq对象时,SelectedItem的{​​{1}}为空,因此不会正确触发事件。 因此,将ListView ItemSource更改为列表可以解决问题。