microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.3k stars 675 forks source link

RadioButtons: SelectionChanged event argument can contain null items as its selected/deselected items #3268

Open Felix-Dev opened 4 years ago

Felix-Dev commented 4 years ago

Describe the bug The RadioButtons.SelectionChanged event args contain null items as selected/deselected items. For example, when setting the initial RadioButtons selection (via code or click interaction), not only does the SelectionChangedEventArgs instance say that an item has been selected, but also that an item has been deselected (SelectionChangedEventArgs.RemovedItems.Count = 1). However, there is no such item being deselected (as none was selected before) and SelectionChangedEventArgs.RemovedItems[0] returns null. Thus this could lead to apps to crash if developers trust SelectionChangedEventArgs.RemovedItems to only contain non-null elements (and the expectation is just that).

Expected behavior No null items should be listed. List count should be 0.

Version Info Microsoft.UI.Xaml 2.4.0 (and earlier) Microsoft.UI.Xaml 2.5 previews

ranjeshj commented 4 years ago

This sounds like a bug but @StephenLPeters can confirm if there was a reason for this behavior.

StephenLPeters commented 4 years ago

Yup, does sound like a bug :/

huoyaoyuan commented 3 years ago

Also hitting this via two way binding of SelectedItem.

SnowyWreath commented 3 years ago

The most common use case for me with RadioButtons would be basing Items or ItemsSource on an array of enums and then two-way binding SelectedItem to a property of that enum type on my view model. This bug prohibits that use case, because trying to cast null to an enum will throw an exception in the auto-generated code of x:bind. I've had to change all of these properties to MyEnum? (and add a bunch of null coalescing throughout my code) because of this issue.

Can we get a status update?

hawkerm commented 3 years ago

Still seeing this in 2.6.2.

The easiest way to compare why this is an issue is to do the following. This is what you can make with a ListView that works fine:

<ListView Header="Size" SelectedItem="{x:Bind MySize, Mode=TwoWay}">
    <x:Int32>3</x:Int32>
    <x:Int32>4</x:Int32>
    <x:Int32>5</x:Int32>
    <x:Int32>6</x:Int32>
</ListView>

If you then just directly swap to RadioButtons, it'll fail and throw a NullReferenceException:

<muxc:RadioButtons Header="Size" SelectedItem="{x:Bind MySize, Mode=TwoWay}">
    <x:Int32>3</x:Int32>
    <x:Int32>4</x:Int32>
    <x:Int32>5</x:Int32>
    <x:Int32>6</x:Int32>
</muxc:RadioButtons>

@Ranjeshj @StephenLPeters seems like @Felix-Dev had a PR opened last year? Is there a way to move this along?

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.

SnowyWreath commented 1 year ago

Bad bot. Do not close.

dnwheeler commented 2 weeks ago

Just a reminder that this issue still exists and is still forcing workarounds for the radio button case.

ccarlo88 commented 4 days ago

So, I have seen the other "Issues" have been closed and started doing some tests. Here is what I discovered.:

Imagine the following code:

<RadioButtons Header="MyChoice" SelectedItem="{x:Bind VM.SelectedItem, Mode=TwoWay}">
    <x:String>Option1</x:String>
    <x:String>Option2</x:String>
</RadioButtons>

When I selected the option, it properly propagates the string value to the ViewModel as expected but not the other way around as it should.

If I try manually doing it like this it also won't work which is odd: MyChoice.SelectedItem= "Option1"

As the above didn't work I would expect index selection to not work too... but it does: MyChoice.SelectedIndex = 0

and in the end if I define a list of strings on the ViewModel then my code becomes: <RadioButtons Header="MyChoice" ItemsSource="{x:Bind VM.ListOfChoices, Mode=OneWay}" SelectedItem="{x:Bind VM.SelectedItem, Mode=TwoWay}" /> and with this code, binding will work on both ways for the selection.

So concluding, my assumption is that the Generic.IList<object> generated from the XAML may have an issue when comparing the value (or type) of the "string" coming back to the UI, making it never finding a match to select and leave the selection as null.

hawkerm commented 3 days ago

@ccarlo88 was that still with UWP and WinUI2 or also with WinUI 3?

ccarlo88 commented 3 days ago

With WinUI3, more precisely WinApp SDK version 1.6.240829007.