.Net Maui:如何在 BindableLayout 内对单选按钮进行分组?

问题描述 投票:0回答:1

我正在开发一个 .Net Maui 应用程序,我必须使用单选按钮来允许用户从列表中选择一个项目。该列表又是另一个列表的一部分。整体结构类似于 Item1(SubItem1,SubItem2,SubItem3,SubItem4), Item2((SubItem1,SubItem2,SubItem3,SubItem4), Item3((SubItem1,SubItem2,SubItem3,SubItem4), Item4((SubItem1,SubItem2,SubItem3,SubItem4) )).

项目源(SubItem1、SubItem2、SubItem3、SubItem4)对于所有项目都是相同的。我正在使用 BindableLayout 和 ContentView 来生成视图。我正在分享示例应用程序中重现的代码问题。 我的要求是为项目选择单个子项目,并且其值应存储在可绑定属性中

SelectedItem

我面临的问题是,每当我为 Item1 选择一个子项目(例如 SubItem1),然后在所有剩余列表 Item2、Item3、Item4 中选择的项目也会使用 SubItem1 进行更新。 我尝试通过使单选按钮的 GroupName 不同并绑定它。这导致了以下问题:如果我选择其中一个单选按钮,则

RadioButton_CheckedChanged
事件将被调用 4 次。 我必须避免在这里多次调用。

有人可以建议我哪里做错了吗?

BindableLayout MainPage 代码

<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="MauiSampleApp.Views.RadioButtonPage"
    xmlns:controls="clr-namespace:MauiSampleApp.Controls"
    Title="RadioButtonPage">
    <VerticalStackLayout
        Spacing="10">
        <VerticalStackLayout
            BindableLayout.ItemsSource="{Binding ModelItemList}">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Grid
                        RowSpacing="6"
                        RowDefinitions="20,auto">

                        <Label
                            Grid.Row="0"
                            Text="{Binding Title}"/>

                        <controls:RadioButtonContentView
                            Grid.Row="1"
                            GroupName="{Binding Title}"
                            ItemSource="{Binding ItemList}"/>
                    </Grid>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </VerticalStackLayout>
    </VerticalStackLayout>
</ContentPage>

主页的代码隐藏

public partial class RadioButtonPage : ContentPage
{
    private RadioButtonViewModel viewModel { get; set; }
    public RadioButtonPage()
    {
    InitializeComponent();
        BindingContext = viewModel = new RadioButtonViewModel();
    }
}

主页的视图模型

public class RadioButtonViewModel : ObservableObject
{
    private List<ModelClass> _modelItemList = new();
    public List<ModelClass> ModelItemList
    {
        get => _modelItemList;
        set => SetProperty(ref _modelItemList, value);
    }

    private PickerItem _selectedItem;
    public PickerItem SelectedItem
    {
        get => _selectedItem;
        set => SetProperty(ref _selectedItem, value);
    }

    public List<PickerItem> RadioButtonList { get; set; }

    public RadioButtonViewModel()
    {
        RadioButtonList = new()
        {
            new PickerItem { Key = "SubItem1", IsSelected = true },
            new PickerItem { Key = "SubItem2", IsSelected = false },
            new PickerItem { Key = "SubItem3", IsSelected = false },
            new PickerItem { Key = "SubItem4", IsSelected = false }
        };

        ModelItemList = new()
        {
            new ModelClass { Title = "Item1", ItemList = RadioButtonList, SelectedItem = RadioButtonList[0] },
            new ModelClass { Title = "Item2", ItemList = RadioButtonList, SelectedItem = RadioButtonList[1] },
            new ModelClass { Title = "Item3", ItemList = RadioButtonList, SelectedItem = RadioButtonList[2] },
            new ModelClass { Title = "Item4", ItemList = RadioButtonList, SelectedItem = RadioButtonList[3] }
        };
    }
}

使用型号:

  1. 模型类
public class ModelClass : ObservableObject
{
    private string _title = "";
    public string Title
    {
        get => _title;
        set => SetProperty(ref _title, value);
    }

    private List<PickerItem> _itemList = new();
    public List<PickerItem> ItemList
    {
        get => _itemList;
        set => SetProperty(ref _itemList, value);
    }
}
  1. 选择器项目
public class PickerItem : ObservableObject
{
    private string _key = "";
    public string Key
    {
        get => _key;
        set => SetProperty(ref _key, value);
    }

    private bool _isSelected = false;
    public bool IsSelected
    {
        get => _isSelected;
        set => SetProperty(ref _isSelected, value);
    }
}

RadioButtonContentView 代码:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiSampleApp.Controls.RadioButtonContentView"
             x:Name="this">

    <VerticalStackLayout
        BindableLayout.ItemsSource="{Binding ItemSource, Source={x:Reference this}}"
        RadioButtonGroup.GroupName="{Binding GroupName, Source={x:Reference this}}">
        <BindableLayout.ItemTemplate>
            <DataTemplate>
                <Grid
                    ColumnSpacing="12"
                    ColumnDefinitions="20,*">

                    <RadioButton
                        Grid.Column="0"
                        IsChecked="{Binding IsSelected}"
                        Value="{Binding .}"
                        CheckedChanged="RadioButton_CheckedChanged"/>

                    <Label
                        Grid.Column="1"
                        Text="{Binding Key}"/>

                    <Grid.GestureRecognizers>
                        <TapGestureRecognizer
                            Tapped="TapGestureRecognizer_Tapped"
                            CommandParameter="{Binding .}"/>
                    </Grid.GestureRecognizers>
                </Grid>
            </DataTemplate>
        </BindableLayout.ItemTemplate>
    </VerticalStackLayout>
</ContentView>

RadioButtonContentView 的代码隐藏

public partial class RadioButtonContentView : ContentView
{
    public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create(
        nameof(SelectedItem),
        typeof(PickerItem),
        typeof(RadioButtonContentView),
        null,
        propertyChanged: SelectedItemPropertyChanged);

    public PickerItem SelectedItem
    {
        get => (PickerItem)GetValue(SelectedItemProperty);
        set => SetValue(SelectedItemProperty, value);
    }

    private static void SelectedItemPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (oldValue is PickerItem oldPickerItem)
        {
            oldPickerItem.IsSelected = false;
        }

        if (newValue is PickerItem newPickerItem)
        {
            newPickerItem.IsSelected = true;
        }
    }

    public static readonly BindableProperty ItemSourceProperty = BindableProperty.Create(
        nameof(ItemSource),
        typeof(List<PickerItem>),
        typeof(RadioButtonContentView),
        new List<PickerItem>());

    public List<PickerItem> ItemSource
    {
        get => (List<PickerItem>)GetValue(ItemSourceProperty);
        set => SetValue(ItemSourceProperty, value);
    }

    public static readonly BindableProperty GroupNameProperty = BindableProperty.Create(
        nameof(GroupName),
        typeof(string),
        typeof(RadioButtonContentView),
        "");

    public string GroupName
    {
        get => (string)GetValue(GroupNameProperty);
        set => SetValue(GroupNameProperty, value);
    }

    public RadioButtonContentView()
    {
        InitializeComponent();
    }

    void RadioButton_CheckedChanged(object sender, CheckedChangedEventArgs e)
    {
        if (sender is RadioButton radioButton)
        {
            if (e.Value)
            {
                var selectedPickerItem = radioButton.Value;
                SelectedItem = (PickerItem)selectedPickerItem;
            }
        }
    }

    void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
    {
        if (e.Parameter is PickerItem selectedPickerItem)
        {
            SelectedItem = selectedPickerItem;
        }
    }
}
mvvm radio-button maui bindable
1个回答
0
投票

在此代码中,您使用 RadioButtonViewModel 中的相同列表实例 RadioButtonList

RadioButtonList = new()
        {
            new PickerItem { Key = "SubItem1", IsSelected = true },
            new PickerItem { Key = "SubItem2", IsSelected = false },
            new PickerItem { Key = "SubItem3", IsSelected = false },
            new PickerItem { Key = "SubItem4", IsSelected = false }
        };

        ModelItemList = new()
        {
            new ModelClass { Title = "Item1", ItemList = RadioButtonList, SelectedItem = RadioButtonList[0] },
            new ModelClass { Title = "Item2", ItemList = RadioButtonList, SelectedItem = RadioButtonList[1] },
            new ModelClass { Title = "Item3", ItemList = RadioButtonList, SelectedItem = RadioButtonList[2] },
            new ModelClass { Title = "Item4", ItemList = RadioButtonList,SelectedItem = RadioButtonList[3] }
        };

要解决此问题,您需要确保每个 ModelClass 实例都有自己的 PickerItems 列表副本。这样,更改一组中选定的单选按钮不会影响其他组。以下是如何调整 ViewModel 为每个 ModelClass 创建单独的 PickerItem 实例:

public RadioButtonViewModel()
{
    ModelItemList = new List<ModelClass>
    {
        new ModelClass { Title = "Item1", ItemList = GetNewRadioButtonList(), SelectedItem = RadioButtonList[0] },
        new ModelClass { Title = "Item2", ItemList = GetNewRadioButtonList(), SelectedItem = RadioButtonList[1] },
        new ModelClass { Title = "Item3", ItemList = GetNewRadioButtonList(), SelectedItem = RadioButtonList[2] },
        new ModelClass { Title = "Item4", ItemList = GetNewRadioButtonList(), SelectedItem = RadioButtonList[3] }
    };
}

private List<PickerItem> GetNewRadioButtonList()
{
    return new List<PickerItem>
    {
        new PickerItem { Key = "SubItem1", IsSelected = false },
        new PickerItem { Key = "SubItem2", IsSelected = false },
        new PickerItem { Key = "SubItem3", IsSelected = false },
        new PickerItem { Key = "SubItem4", IsSelected = false }
    };
}

© www.soinside.com 2019 - 2024. All rights reserved.