diff --git a/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs b/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
index 265dcf49a373..e1a324efa0c9 100644
--- a/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
+++ b/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
@@ -24,6 +24,8 @@ public RadioButtonGroupController(Maui.ILayout layout)
_layout = (Element)layout;
_layout.ChildAdded += ChildAdded;
_layout.ChildRemoved += ChildRemoved;
+ _layout.DescendantAdded += DescendantAdded;
+ _layout.DescendantRemoved += DescendantRemoved;
if (!string.IsNullOrEmpty(_groupName))
{
@@ -97,6 +99,30 @@ void ChildRemoved(object sender, ElementEventArgs e)
}
}
+ void DescendantAdded(object sender, ElementEventArgs e)
+ {
+ if (string.IsNullOrEmpty(_groupName) || _layout == null)
+ {
+ return;
+ }
+
+ if (e.Element is RadioButton radioButton)
+ {
+ AddRadioButton(radioButton);
+ }
+ }
+
+ void DescendantRemoved(object sender, ElementEventArgs e)
+ {
+ if (e.Element is RadioButton radioButton)
+ {
+ if (groupControllers.TryGetValue(radioButton, out _))
+ {
+ groupControllers.Remove(radioButton);
+ }
+ }
+ }
+
internal void HandleRadioButtonValueChanged(RadioButton radioButton)
{
if (radioButton?.GroupName != _groupName)
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml
new file mode 100644
index 000000000000..287d5fedd504
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml.cs
new file mode 100644
index 000000000000..caa69fa751ce
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue33264.xaml.cs
@@ -0,0 +1,68 @@
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace Maui.Controls.Sample.Issues;
+
+[Issue(IssueTracker.Github, 33264, "RadioButtonGroup not working with CollectionView", PlatformAffected.All)]
+public partial class Issue33264 : ContentPage
+{
+ public Issue33264()
+ {
+ InitializeComponent();
+ BindingContext = new Issue33264ViewModel();
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(500), () =>
+ {
+ CaptureState("OnAppearing");
+ });
+ }
+
+ private void CaptureState(string context)
+ {
+ var vm = BindingContext as Issue33264ViewModel;
+ Console.WriteLine($"=== STATE CAPTURE: {context} ===");
+ Console.WriteLine($"SelectedValue: {vm?.SelectedValue ?? "null"}");
+ Console.WriteLine("=== END STATE CAPTURE ===");
+ }
+}
+
+public class Issue33264ViewModel : INotifyPropertyChanged
+{
+ private string _selectedValue;
+
+ public ObservableCollection Choices { get; } = new ObservableCollection
+ {
+ "Choice 1",
+ "Choice 2",
+ "Choice 3"
+ };
+
+ public string SelectedValue
+ {
+ get => _selectedValue;
+ set
+ {
+ if (_selectedValue != value)
+ {
+ Console.WriteLine($"=== BINDING UPDATE: SelectedValue changing from '{_selectedValue}' to '{value}' ===");
+ _selectedValue = value;
+ OnPropertyChanged();
+ OnPropertyChanged(nameof(SelectedValueDisplay));
+ }
+ }
+ }
+
+ public string SelectedValueDisplay => string.IsNullOrEmpty(SelectedValue) ? "None" : SelectedValue;
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33264.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33264.cs
new file mode 100644
index 000000000000..1e239d7e44ba
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33264.cs
@@ -0,0 +1,52 @@
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues;
+
+public class Issue33264 : _IssuesUITest
+{
+ public override string Issue => "RadioButtonGroup not working with CollectionView";
+
+ public Issue33264(TestDevice device) : base(device) { }
+
+ [Test]
+ [Category(UITestCategories.RadioButton)]
+ public void RadioButtonGroupBindingWorksInsideCollectionView()
+ {
+ // Wait for page to load
+ App.WaitForElement("ChoicesCollectionView");
+ App.WaitForElement("SelectedValueLabel");
+
+ // Give it a moment to render
+ Task.Delay(500).Wait();
+
+ // Initially, SelectedValue should show "None"
+ var initialValue = App.FindElement("SelectedValueLabel").GetText();
+ Console.WriteLine($"Initial SelectedValue: '{initialValue}'");
+ Assert.That(initialValue, Is.EqualTo("None"), "Initial value should be 'None'");
+
+ // Tap "Choice 2" radio button
+ App.WaitForElement("Choice 2");
+ App.Tap("Choice 2");
+
+ // Wait for binding update
+ Task.Delay(1000).Wait();
+
+ // Verify SelectedValue is updated
+ var selectedValue = App.FindElement("SelectedValueLabel").GetText();
+ Console.WriteLine($"After tapping 'Choice 2', SelectedValue: '{selectedValue}'");
+ Assert.That(selectedValue, Is.EqualTo("Choice 2"), "SelectedValue should be updated via binding when RadioButton is checked");
+
+ // Tap "Choice 3" radio button
+ App.Tap("Choice 3");
+
+ // Wait for binding update
+ Task.Delay(1000).Wait();
+
+ // Verify SelectedValue is updated again
+ selectedValue = App.FindElement("SelectedValueLabel").GetText();
+ Console.WriteLine($"After tapping 'Choice 3', SelectedValue: '{selectedValue}'");
+ Assert.That(selectedValue, Is.EqualTo("Choice 3"), "SelectedValue should be updated when different RadioButton is checked");
+ }
+}