XAML 如何传递多个参数

6xfqseft  于 2023-11-14  发布在  其他
关注(0)|答案(2)|浏览(99)

我想要完成的

我有一个EventToCommandBehavior命令,它将一个事件参数作为参数传递给命令:“MykedChanged”事件参数。我还需要它传递一个普通的旧参数。
x1c 0d1x的数据
可能只是语法问题,我还没找到合适的文档。希望如此。

我当前的代码

非常简单的东西,真的。该命令发生在CollectionView中的Chcekbox控件中。基本上,我有一个类型列表“Video”(我自己的类)显示,每个旁边有一个复选框。当用户单击复选框时,我转到一个方法。我需要传递两个参数:
(1)CheckChangedEventArg,我传递它,
(2)我们正在看的对象,“Video”,我不知道如何用CheckChangedEventArg传递沿着。
下面是XAML:

<CollectionView ItemsSource="VideoList">
  ...
    <DataTemplate x:DataType="model:Video">
        ...
               <CheckBox>
                   <CheckBox.Behaviors>
                       <toolkit:EventToCommandBehavior
                            x:TypeArguments="CheckedChangedEventArgs"
                            EventName="CheckedChanged"
                            Command="{Binding Source={x:Reference this}, Path=BindingContext.AddRemoveFromListCommand}"/>
                  </CheckBox.Behaviors>
              </CheckBox>
       ...
   </DataTemplate>
  ...
</CollectionView>

字符串
下面是ViewModel:

[RelayCommand]
public void AddRemoveFromList(CheckedChangedEventArgs args)
{
    if (args.Value)
    {
          // do the thing
    }
    else
    {
          // do the other thing
    }
}


请注意,这是 * 工作代码 *,只是它只传递CheckedChangedEVentArgs。我需要它传递CheckedChangedEventArgsVideo(在<DataTemplate/>属性中提到)。

我尝试了什么?

我尝试了reading the docs。答案可能在那里,但我找不到它。属性xTypeArguments的名称是复数,这让我想,也许我可以简单地添加另一个参数?
而且,唉,我可以访问该属性中的Video对象!

这让我想到,也许我需要做的就是:

<CheckBox.Behaviors>
    <toolkit:EventToCommandBehavior
            x:TypeArguments="CheckedChangedEventArgs, Video (model)"
            EventName="CheckedChanged"
            Command="{Binding Source={x:Reference this}, Path=BindingContext.AddRemoveFromListCommand}" 
            CommandParameter="{Binding VideoFilename}"
            />
</CheckBox.Behaviors>


并且:

[RelayCommand]
    public void AddRemoveFromList(CheckedChangedEventArgs args, Video video)
    {
            ...
    }


但这不管用。
我也做了很多其他的事情,包括CommandParameter,但是都没有用。
有人知道该怎么做吗?

解决方案更新

Stephen Quan的建议奏效了。谢谢你,Quan先生。下面是解决方案:
我的整个目标是:当用户选择CollectionView中的一个对象时,它会被添加到ObservableCollection列表中,并传递到应用程序的另一部分。



解决方案如下:

  • Video对象中添加一个布尔属性。我们称之为VideoIsChecked
  • CollectionView中,当复选框被选中时,将VideoIsChecked绑定到本机Checkbox属性IsChecked
  • 从这里我可以简单地遍历Video对象的列表。如果Video对象的VideoIsChecked属性为true,则将其添加到“User Selected Videos”列表中。

这是新的Checkbox Xaml。我完全删除了选中复选框时触发的方法,因为它不再需要,并且属性Video.VideoIsChecked绑定到IsChecked Checkbox属性。

<CheckBox x:Name="checkBox"
          ScaleX="1.5"
          ScaleY="1.5"
          Color="#000063"
          HorizontalOptions="End"
          IsChecked="{Binding VideoIsChecked, Mode=TwoWay}" />


ViewModel中,我声明了属性:

[ObservableProperty]
    private bool videoIsChecked;


我在模型Video中声明属性:

namespace Project.Model;
public class Video
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public bool VideoIsChecked { get; set; }
      ...
}


最后,当用户选择了他们的视频并点击一个类似“完成”的按钮时,我会创建一个所选视频的列表并将其发送到下一页。下面是我浏览视频并查看哪些视频具有VideoIsChecked is true的部分:

private async Task CreateListOfSelectedVideos()
{
   foreach (Video video in Videos)
   {
      if (video.VideoIsChecked)
      {
         SelectedVideos.Add(video);
      }
   }

   ...

}


就这样!很好,简单的解决办法!

ijxebb2r

ijxebb2r1#

在这个答案中,我将忽略您问题中的EventToCommandBehavior部分,但是,我将专注于您的核心需求:

  1. 1.对视频视图模型中的复选框更改做出React,
  2. 1.维护选定视频的列表
    第一部分可以通过IsChecked="{Binding VideoIsChecked, Mode=TwoWay}"完成,这样你的视频视图模型就可以通过VideoIsChecked设置器接收通知。第二部分可以通过LINQ或VideoIsChecked过滤器在列表上调用.Where()来完成。
    下面是视频视图模型(注意,因为从您的评论中,我得出您正在使用CommunityToolkit.Mvvm,所以,我将在这里使用CommunityToolkit.Mvvm功能):
// Video.cs ...

public partial class Video : ObservableObject
{
    [ObservableProperty]
    private int _id;

    [ObservableProperty]
    private bool _videoIsChecked = false;

    // ...
}

字符串
ObservableObject有一个PropertyChanged事件处理程序,我们将使用它来冒泡从视频视图模型到父视图模型的更改。
为了简单起见,我让MainPage作为父视图模型。它有VideoListSelectedVideos两个集合。SelectedVideos属性是用一个getter函数实现的,它动态地评估所选的视频集合,但我们只在看到VideoList集合中的任何Videos事件时才触发重新评估:

// MainPage.xaml.cs ...

public partial class MainPage : ContentPage
{
    public List<Video> VideoList { get; } = new List<Video>()
    {
        new Video() { Id=1, VideoIsChecked = false },
        new Video() { Id=2, VideoIsChecked = false },
        new Video() { Id=3, VideoIsChecked = false },
    };

    public List<Video> SelectedVideos => VideoList.Where(v => v.VideoIsChecked).ToList();

    public MainPage()
    {
        InitializeComponent();
        BindingContext = this;
        for (int i = 0; i < VideoList.Count; i++)
            VideoList[i].PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(Video.VideoIsChecked))
                    OnPropertyChanged(nameof(SelectedVideos));
            };
    }
}


下面是一个最小的XAML,显示了父VideoListCheckBox以及到SelectedVideos集合的后续绑定:

<!-- MainPage.xaml -->
<VerticalStackLayout>
    <CollectionView ItemsSource="{Binding VideoList}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="local:Video">
                <HorizontalStackLayout>
                    <Label Text="{Binding Id, StringFormat='Video Id: {0}'}" VerticalOptions="Center" />
                    <CheckBox IsChecked="{Binding VideoIsChecked, Mode=TwoWay}"  VerticalOptions="Center" />
                </HorizontalStackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

    <Label Text="{Binding SelectedVideos.Count, StringFormat='Selected Videos: {0}'} "/>

    <CollectionView ItemsSource="{Binding SelectedVideos}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="local:Video">
                <Label Text="{Binding Id, StringFormat='Selected Video Id: {0}'}"/>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</VerticalStackLayout>


可以在这里找到一个工作示例:https://github.com/stephenquan/StackOverflow.Maui/tree/main/StackOverflow.Maui.Mvvm.CheckBox


的数据

eaf3rand

eaf3rand2#

不需要同时传递CheckedChangedEventArgsVideo (model),我们可以将视频Item(包括CheckBox的选中值)作为一个整体传递。
你可以在你的Video模型中添加一个bool变量(例如public bool VideoIsChecked),并为你的Video Item实现INotifyPropertyChanged(假设Videl模型是Video.cs),然后将它绑定到这个CheckBox的属性VideoIsChecked。当然,如果你使用nuget MVVM Toolkit,你可以简单地使用下面的代码。
一旦我们选中或取消选中CheckBox,这个变量的值将被更新。所以,我们可以传递整个Video Item。
你可以参考下面的代码。在这里,我继承了ObservableObject的视频模型不是INotifyPropertyChanged

视频.cs

public partial class Video:ObservableObject
{
    //I add a property to identify the name of the video
    public string Title { get; set; }

    [ObservableProperty]
    public bool videoIsChecked;
}

字符串

MyViewModel.cs

在这里,我们可以通过以下代码获得整个视频项目:

public ICommand AddRemoveFromListCommand { get; set; }

AddRemoveFromListCommand = new Command<Video>(DoSomething);

private void DoSomething(Video item)
    {
        if (item != null)
        {
            if (item.VideoIsChecked)
            {
                // you also need to add some other logic codes here
                System.Diagnostics.Debug.WriteLine($"{item.Title}");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine($"{item.Title}");

            }
        }
    }


可以参考MyViewModel的完整代码:

MyViewModel.cs

public class MyViewModel
{
    public ObservableCollection<Video> VideoList { get; set; }

    //define the AddRemoveFromListCommand for the CheckBox
    public ICommand AddRemoveFromListCommand { get; set; }

    public ObservableCollection<Video> SelectedVideos { get; set; }
    // you can  get all the selected Videos based on the value of property videoIsChecked
    public ICommand GetSelectedVideosCommand { get; set; }

    public MyViewModel() {
        VideoList = new ObservableCollection<Video>();// initialize the VideoList
        VideoList.Add(new Video { Title="video1", VideoIsChecked = true});
        VideoList.Add(new Video { Title="video2", VideoIsChecked = false});
        VideoList.Add(new Video { Title="video3", VideoIsChecked = false});

        SelectedVideos = new ObservableCollection<Video>(); // initialize the SelectedVideos

        AddRemoveFromListCommand = new Command<Video>(DoSomething);

        GetSelectedVideosCommand= new Command(GetAllSelectedVideos);

    }

    private void GetAllSelectedVideos()
    {
        foreach (Video video in VideoList)
        {
            if (video.VideoIsChecked)
            {
                // add the video to the selectedlist
                SelectedVideos.Add(video);
            }
        }

    }

    private void DoSomething(Video item)
    {
        if (item != null)
        {
            if (item.VideoIsChecked)
            {
                // you also need to add some other logic codes here
                System.Diagnostics.Debug.WriteLine($"{item.Title}");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine($"{item.Title}");

            }
        }
    }
}


3.使用示例:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:viewmodels="clr-namespace:MauiVideoListApp.ViewModels"
             x:Class="MauiVideoListApp.MainPage">

    <ContentPage.BindingContext>
        <viewmodels:MyViewModel></viewmodels:MyViewModel>
    </ContentPage.BindingContext>

    <VerticalStackLayout>
        <CollectionView ItemsSource="{Binding VideoList}" x:Name="myCollectionView">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <HorizontalStackLayout>
                        <CheckBox Color="#0B4C90" IsChecked="{Binding VideoIsChecked}">
                            <CheckBox.Behaviors>
                                <toolkit:EventToCommandBehavior
                                    Command="{Binding BindingContext.AddRemoveFromListCommand, Source={x:Reference myCollectionView}}"
                                    CommandParameter="{Binding .}"
                                    EventName="CheckedChanged" />
                            </CheckBox.Behaviors>

                        </CheckBox>
                        <Label Text="{Binding Title}"
                                       FontSize="20"
                                       FontAttributes="Bold"
                                       TextColor="#0B4C90"/>
                    </HorizontalStackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

        <Button Text="Get Result" Command="{Binding GetSelectedVideosCommand}"  />
    </VerticalStackLayout>

</ContentPage>

注:

我还添加了一个按钮,以获得所有选定的视频列表.

// you can  get all the selected Videos based on the value of property videoIsChecked
    public ICommand GetSelectedVideosCommand { get; set; }

    GetSelectedVideosCommand= new Command(GetAllSelectedVideos);

   private void GetAllSelectedVideos()
    {
        foreach (Video video in VideoList)
        {
            if (video.VideoIsChecked)
            {
                // add the video to the selectedlist
                SelectedVideos.Add(video);
            }
        }

    }

相关问题