检测标签上的点击,在 ViewCell 内,在 ListView 内

Posted

技术标签:

【中文标题】检测标签上的点击,在 ViewCell 内,在 ListView 内【英文标题】:Detecting tap on label, inside ViewCell, inside ListView 【发布时间】:2016-12-26 06:50:54 【问题描述】:

我正在尝试处理类似的事情(从 UI 角度),以:

为了调用两个不同的业务逻辑:

点击 ViewCell 元素本身(在 ListView 内) - 例如导航到不同的页面 在给定 ViewCell 元素内的 Label 元素 (Clickable Label) 上点击 - 例如删除给定对象或其他内容

我想在页面 ViewModel 内包含整个“点击”逻辑。

根据 Xamarin 论坛的建议,我可以调用一些从单元格中“点击”我的 delete 操作的逻辑,但是直接在我的数据模型中 - 这在我的 PoV 中并不是一个好的解决方案,因为我想操作我的 List 集合(所以最可取的方法是在页面 ViewModel 上有这个逻辑)。

我现在拥有的:

我的页面查看 XAML 代码如下:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App.Views.TestView">
  <ContentPage.Content>
    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        <ListView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemsSource="Binding MyItemsCollection" SelectedItem="Binding SelectedItem">
          <ListView.ItemTemplate>
            <DataTemplate>
              <ViewCell>
                <StackLayout Orientation="Horizontal">

                  <!-- Name Label -->
                  <Label Text="Binding Name" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" />

                  <!-- Delete "Icon" -->
                  <Label Text="Clickable Label" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
                    <Label.GestureRecognizers>
                      <TapGestureRecognizer Command="Binding OnClickableLabel" CommandParameter="Binding ." />
                    </Label.GestureRecognizers>
                  </Label>

                </StackLayout>
              </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

我的页面查看 C# 代码看起来像(没有特定代码,除了将 **BindingContext* 绑定到页面 ViewModel):

public partial class TestView : ContentPage

    public TestView()
    
        InitializeComponent();
        BindingContext = ServiceLocator.Current.GetInstance<TestViewModel>();
    

我的页面ViewModel C#代码如下:

public class TestViewModel : ViewModelBase

    public TestViewModel()
    
        MyItemsCollection = GetMyItemsCollection();
    

    private List<MyItem> GetMyItemsCollection()
    
        return new List<MyItem>
        
            new MyItem
            
                ID = 1L,
                Name = "Item 1 Name"
            ,
            new MyItem
            
                ID = 2L,
                Name = "Item 2 Name"
            ,
            new MyItem
            
                ID = 3L,
                Name = "Item 3 Name"
            
        ;
    

    private List<MyItem> _myItemsCollection  get; set; 

    public List<MyItem> MyItemsCollection
    
        get
        
            return _myItemsCollection;
        
        set
        
            _myItemsCollection = value;
            RaisePropertyChanged();
        
    

    private MyItem _SelectedItem  get; set; 

    public MyItem SelectedItem
    
        get
        
            return _SelectedItem;
        
        set
        
            if (_SelectedItem != value)
            
                _SelectedItem = value;
                RaisePropertyChanged();

                Debug.WriteLine("SelectedItem: " + _SelectedItem.Name);
            
        
    

    private RelayCommand<object> _OnClickableLabel;

    public RelayCommand<object> OnClickableLabel
    
        get  return _OnClickableLabel ?? (_OnClickableLabel = new RelayCommand<object>((currentObject) => Test(currentObject))); 
    

    private void Test(object currentObject)
    
        Debug.WriteLine("This should work... but it's not working :(");
    

我的数据模型代码如下:

public class MyItem

    public long ID  get; set; 
    public string Name  get; set; 

    private RelayCommand<object> _OnClickableLabel;

    public RelayCommand<object> OnClickableLabel
    
        get  return _OnClickableLabel ?? (_OnClickableLabel = new RelayCommand<object>((currentObject) => Test(currentObject))); 
    

    private void Test(object currentObject)
    
        Debug.WriteLine("This works... but it's not good idea, to have it here...");
    

知道需要更改什么,以便直接在我的页面 ViewModel 内调用 OnClickableLabel 吗? 我知道,这有问题:

<TapGestureRecognizer Command="Binding OnClickableLabel" CommandParameter="Binding ." />

但不知道是什么:/。

帮助!非常感谢。

【问题讨论】:

MyItem中创建一个自定义事件,当点击删除标签时触发它(使用TapGestureRecognizer)。从任何地方订阅该事件,或者在您的情况下,从 ViewModel 订阅该事件,并以您想要的任何方式处理这些点击。 好的,这可能是一种解决方法......但是让我们想象一下,我的应用程序将包含具有不同列表的多个页面......我希望避免在此类事件中发送和订阅:/还有什么想法吗?谢谢 您的意思是您不想单独订阅/取消订阅每个项目? 不不,我的意思是 - 我不想订阅/取消订阅每个页面,我想在其中使用 ListView,使用这样的自定义命令,应该在 调用TapGestureRecognizer. 需要在构造函数中初始化命令吗?即在构造函数之外: public RelayCommand OnClickableLabel get; 然后在构造函数 OnClickableLabel = new RelayCommand 等 【参考方案1】:

好的,我通过扩展 XAML 代码找到了解决方案:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App.Views.TestView" x:Name="Page">
  <ContentPage.Content>
    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        <ListView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemsSource="Binding MyItemsCollection" SelectedItem="Binding SelectedItem">
          <ListView.ItemTemplate>
            <DataTemplate>
              <ViewCell>
                <StackLayout Orientation="Horizontal">

                  <!-- Name Label -->
                  <Label Text="Binding Name" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" />

                  <!-- Delete "Icon" -->
                  <Label Text="Clickable Label" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
                    <Label.GestureRecognizers>
                      <TapGestureRecognizer Command="Binding Path=BindingContext.OnClickableLabel, Source=x:Reference Page" CommandParameter="Binding ." />
                    </Label.GestureRecognizers>
                  </Label>

                </StackLayout>
              </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

之后,我的页面 ViewModel 中调用了 OnClickableLabel 命令,正如预期的那样:)。

如果有人知道“更好”的解决方案(从 XAML 代码的角度来看更好),我希望看到它;)。

非常感谢大家!

【讨论】:

【参考方案2】:

继续@Namek 所说的,我建议先获取列表视图项的对象,然后调用命令或视图模型方法。

有关更多信息,您可以参考我关于交互式 Listview 的博客文章https://adityadeshpandeadi.wordpress.com/2018/07/15/the-more-interactive-listview/

随时光临。 :)

【讨论】:

以上是关于检测标签上的点击,在 ViewCell 内,在 ListView 内的主要内容,如果未能解决你的问题,请参考以下文章

如何在viewCell中获取按钮的id

iOS WKWebview如何检测我何时点击<a>标签内的图像

Xamarin.Forms MVVM TapGestureRecognizer 到 ListView 的 ViewCell 中的标签(在部分文件中)

约束 UIView 内的标签,该标签位于可扩展 collectionViewCell 内

Xamarin在ListView中使用StackLayout可见性形成跨平台问题

UIButton 标签检测点击特定文本