Maui syntax to use converter inside of a C# method

149 views Asked by At

What I'm trying to accomplish

In a CollectionView, I display a list of objects. In each display there's a checkbox next to it.

Ideally, when the user checks or un-checks the checkbox I go into a method where I can do stuff with the object:

enter image description here

The above is fantasy code.

The actual code

In reality, when the user checks/unchecks the box the code goes into a method, only I'm passing this object CheckedChangedEventArgs into the method.

I need to convert that object ChcekedChangedEventArgs into a bool. (Note that I'm using the MvvM pattern, so I'm not working with code-behind.)
enter image description here

A kind soul gave me some code that will probably do the converting:

public class CheckedChangedArgsConverter : BaseConverterOneWay<CheckedChangedEventArgs, bool>
{
    public override bool DefaultConvertReturnValue { get; set; } = false;

    public override bool ConvertFrom(CheckedChangedEventArgs value, CultureInfo culture)
    {
        return value.Value;
    }
}

However, I don't know how to use the converter. It seems like I have two options here:

  1. Run the converter from the Xaml and have it run before the command AddRemoveFromList is called so I can pass in the converted Boolean, or
  2. Run the converter code from the C# class, something like this:
    enter image description here

The fact is, I have no idea how to do either. Can anyone help?

====================================================================

EDIT: the object CheckedChangedEventArgs getting passed into the C# method is ALWAYS null.

Here's my Checkbox code. I'm using the EventToCommandBehavior because it's the only thing I can think of to call a command from inside the Checkbox:

<CheckBox x:Name="checkBox"
          ScaleX="1.5"
          ScaleY="1.5"
          Color="#000063"
          HorizontalOptions="End">
    <CheckBox.Behaviors>
        <toolkit:EventToCommandBehavior EventName="CheckedChanged"
                                        Command="{Binding Source={x:Reference this}, 
                                                  Path=BindingContext.AddRemoveFromListCommand}"/>                                       
    </CheckBox.Behaviors>
</CheckBox>

I added x:TypeArguments to the Checkbox:

<CheckBox x:Name="checkBox"
          ScaleX="1.5"
          ScaleY="1.5"
          Color="#000063"
          HorizontalOptions="End">
    <CheckBox.Behaviors>
        <toolkit:EventToCommandBehavior
                x:TypeArguments="CheckedChangedEventArgs"
                                        EventName="CheckedChanged"
                                        Command="{Binding Source={x:Reference this}, Path=BindingContext.AddRemoveFromListCommand}" />
    </CheckBox.Behaviors>
</CheckBox>

And that did the trick.

1

There are 1 answers

2
Jessie Zhang -MSFT On BEST ANSWER

You can just add a bool variable(e.g. public bool VideoIsChecked) to your Video model and implement INotifyPropertyChanged for your Video Item(Suppose the Videl Model is Video.cs), then bind it to the property VideoIsChecked of this CheckBox. Of course, if you use nuget MVVM Toolkit,you can simply this code.

Once we check or uncheck the CheckBox, the value of this variable will be updated. So, we can pass the whole Video Item.

You can refer to the following code. Here, I inherited the ObservableObject for the Video model not INotifyPropertyChanged.

Video.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

Here, we can get the whole video item by following code:

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

            }
        }
    }

You can refer to the whole code of 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.Usage example:

 <?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>

Note:

I also added a Button to get all the selected video list.

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

    }