Home > OS >  .Net Maui: How can I update a single item in an Observable Collection using radio buttons?
.Net Maui: How can I update a single item in an Observable Collection using radio buttons?

Time:02-04

I am building a .Net maui app and I have a list of questions that I need to be collecting answers in a carousel way using radio buttons, I am using MVVM to update the answer the user will select but when the user selects the question it not only updates the answer on the item displayed but in all of the items in the collection, here is my code:

Model:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace TestMauiApp.Model
{
    public class Question:INotifyPropertyChanged
    {       

        public string Name { get; set; }

        string answer;

        public string Answer`your text`
        {
            get => answer;

            set
            {
                answer = value;
                OnPropertyChanged(nameof(Answer));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        void OnPropertyChanged([CallerMemberName] string answer = "") =>
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(answer));
      
    }
}

ViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;

using TestMauiApp.Model;

namespace TestMauiApp.ViewModel
{
    public partial class LightDutyViewModel : ObservableObject
    {
        public LightDutyViewModel() {
            Questions = new ObservableCollection<Question> {
                new Question { Name = "Seat Belts Condition"  },
                new Question { Name = "Horns and Siren Operation" },
                new Question { Name = "Condition of Glass/Mirrors/Adjustment" },
                new Question { Name = "Fuel Level" },
                new Question { Name = "Radio operation" }
             };
         }

        [ObservableProperty]
        ObservableCollection<Question> questions;
    }
}

Xaml:

<?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"
            x:Class="TestMauiApp.LightDuty"
            xmlns:model="clr-namespace:TestMauiApp.Model"
            xmlns:viewmodel="clr-namespace:TestMauiApp.ViewModel"
            x:DataType="viewmodel:LightDutyViewModel"
            Title="Light Duty"
             BackgroundColor="#F2FCFF"
             
    <StackLayout>
        <CarouselView                 
        ItemsSource="{Binding Questions}" >
        <CarouselView.ItemTemplate>
            <DataTemplate  x:DataType="model:Question">
                <StackLayout HeightRequest="500">
                    <Frame  
                            HorizontalOptions="Center"
                            VerticalOptions="CenterAndExpand"
                         CornerRadius="5"
                       Margin="20"
                            BorderColor="Transparent"
                            BackgroundColor="#F2FCFF"                            
                            HeightRequest="400">
                            <StackLayout>
                            <Label Text="{Binding Name}"
                               FontAttributes="Bold"
                               FontSize="18"
                              HorizontalOptions="Center"
                               VerticalOptions="Center"/>

                            <StackLayout RadioButtonGroup.GroupName="questiongroup"
                                         RadioButtonGroup.SelectedValue="{Binding Answer}">
                              <RadioButton Content="OK" Value="OK" />
                              <RadioButton Content="Fail" Value="Fail" />
                            </StackLayout>                          
                                <Label Text="{Binding Answer}"
                               FontAttributes="Bold"
                               FontSize="18"
                              HorizontalOptions="Center"
                               VerticalOptions="Center" />
                            
                        </StackLayout>
                    </Frame>
                    
                </StackLayout>
            </DataTemplate>
        </CarouselView.ItemTemplate>
    </CarouselView>

    </StackLayout>
</ContentPage>

xaml.cs:

using TestMauiApp.ViewModel;
namespace TestMauiApp;

public partial class LightDuty : ContentPage
{
    public LightDuty()
    {
    InitializeComponent();   
        BindingContext = new LightDutyViewModel();
    }
}

The way I found this to only update the current answer was to use dropdowns instead of radio buttons but they prefer the radio buttons, the only difference will be the xaml file like this:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            x:Class="TestMauiApp.LightDuty"
            xmlns:model="clr-namespace:TestMauiApp.Model"
            xmlns:viewmodel="clr-namespace:TestMauiApp.ViewModel"
            x:DataType="viewmodel:LightDutyViewModel"
            Title="Light Duty"
             BackgroundColor="#F2FCFF">
<StackLayout>
    <CarouselView                 
    ItemsSource="{Binding Questions}" >
    <CarouselView.ItemTemplate>
        <DataTemplate  x:DataType="model:Question">
            <StackLayout HeightRequest="500">
                <Frame  
                        HorizontalOptions="Center"
                        VerticalOptions="CenterAndExpand"
                     CornerRadius="5"
                   Margin="20"
                        BorderColor="Transparent"
                        BackgroundColor="#F2FCFF"                            
                        HeightRequest="400">
                        <StackLayout>
                        <Label Text="{Binding Name}"
                           FontAttributes="Bold"
                           FontSize="18"
                           HorizontalOptions="Center"
                           VerticalOptions="Center"/>

                            <Picker Title="Select Option" SelectedItem="{Binding Answer}">
                              <Picker.ItemsSource>
                                  <x:Array Type="{x:Type x:String}">
                                      <x:String>OK</x:String>
                                      <x:String>Fail</x:String>
                                  </x:Array>
                               </Picker.ItemsSource>
                             </Picker>
                      
                            <Label Text="{Binding Answer}"
                             FontAttributes="Bold"
                             FontSize="18"
                             HorizontalOptions="Center"
                             VerticalOptions="Center" />
                        
                    </StackLayout>
                </Frame>
                
            </StackLayout>
        </DataTemplate>
    </CarouselView.ItemTemplate>
</CarouselView>

</StackLayout>

CodePudding user response:

For iOS, there is an existing issue on Github: Xamarin radio button not working properly #11659. According to hartez comment, it's caused by design, seems like a reuse problem. You may see radio button behave strange in CarouselView for iOS even though you change different group name.

For Android, it worked well. Just as ToolmakerSteve and FreakyAli mentioned, add a Groupname property for Question Model and bind it.

<StackLayout RadioButtonGroup.GroupName="{Binding Groupname}" ...

Hope it works for you.

CodePudding user response:

First, I think you should be using checkbox or switch, for indicating bool values on your interface.

Second, Group names should be different, that is true. But I do not think that binding is the best way in your situation.

There is old way to handle RadioButtons, without defining any Group, Selected value, or anything of the sort.

Nothing is stopping you from using ValueConverter and setting the ConverterParameter for each RadioButton. (If you can write IntToBoolConverter, you will be fine. When the value is 1, first selected, 2 - second, and so on)

(You can also do this with Enums. So it does not have to be int. Just trying to explain concept.)

I am still using this here and there, and it is working perfectly on MAUI.

Edit: Just noticed you are using Frames, right now they are too many issues with them. I advise you to use Borders instead if you run into them.

  • Related