Maui icon indicating copy to clipboard operation
Maui copied to clipboard

[Bug] EnumToIntConverter throws an unhandled exception when the picker tries to convert -1

Open emorell96 opened this issue 2 years ago • 15 comments

Description

The EnumToIntConverter doesn't mix well sometimes with Pickers in MAUI. Sometimes the Picker seems to try to convert -1, and it of course fails since the enum doesn't have that value.

I have created a gif showing the issue in the app I am developing. If I find some time I'll try to create a repo project, but in short the issue seems related to MAUI reloading a hidden Picker. And the index for some reason is set to -1 at one point.

I have solved this for the mean time in my code by copying the source code from here: https://github.com/CommunityToolkit/Maui/blob/6d3ecd66810077bb102436cf2d264219d3cd7c04/src/CommunityToolkit.Maui/Converters/EnumToIntConverter.shared.cs#L41

And replacing that line with a return null.

Link to Reproduction Sample

You can take a look at the code source of my project here: https://github.com/StockDrops/OpenStockApp/blob/a7cb138c8f8ef1acb6ba8cb196403b74e550ba0e/OpenStockApp/Views/ModelOptionsView.xaml#L120

I basically have a view with a picker and an enum, and when I load the items into the picker, navigate to another page with the another instance of the view inside, load items again, and then go back to the original view, the MAUI framework seems to set SelectedIndex to -1 and this of course breaks the converter since it throws that it doesn't find -1 in the enum, but I have 0 control over this since it's just the way MAUI seems to work.

Expected Behavior

Shoudn't throw that exception for -1 seems it seems like an important value for MAUI.

Actual Behavior

Throws an exception, causing an unhandled app exception crashing the app.

Basic Information

  • Version with issue: RC1
  • Last known good version: Preview 14
  • IDE: VS 2022 Preview (latest)
  • Platform Target Frameworks:
    • UWP: This happens on Windows, I haven't tested in on other frameworks.

Workaround

Copy the source code, change the line 120 to return null.

Reproduction imagery

Animation

emorell96 avatar Apr 22 '22 21:04 emorell96

Interesting! I wonder if the Picker defaults a value to -1?

brminnick avatar Apr 22 '22 22:04 brminnick

@brminnick yes it does image

emorell96 avatar Apr 22 '22 22:04 emorell96

From here: https://github.com/dotnet/maui/blob/8b56c0b1e703804631f280370fd34789ffa21b16/src/Controls/src/Core/Picker.cs#L32

emorell96 avatar Apr 22 '22 22:04 emorell96

I can't work out what the fix here would be. Obviously the Picker binding defaults to -1 but what should the converter return in this scenario?

An initial workaround would be to add a -1 value to the enum. It might even be the solution

bijington avatar Apr 23 '22 22:04 bijington

I'd say it should depend if the Enum defines a value for -1.

If it doesn't returning null seems to work okay in my app.

If it does then that's tricky and I don't know what would be a good enough general approach if there's even one (at least for this use case of EnumToInt converter).

emorell96 avatar Apr 24 '22 02:04 emorell96

It maybe used not only with Picker. So I suggest to add some kind of DefaultValue:

int? DefaultValue = null;

…

if (DefaultValue.HasValue) return DefaultValue.Value;
else 
throw new InvalidEnumArgumentExceptuin(..);

VladislavAntonyuk avatar Apr 24 '22 05:04 VladislavAntonyuk

I would extend this question... If the default value is -1, I believe that the control isn't fully initialized yet, so the MAUI framework shouldn't trigger the Converters, Triggers, etc. I'm curious in which scenarios this happens.

@emorell96 Could you attach a small repro?

pictos avatar Apr 24 '22 16:04 pictos

I had similar issue with ListView, it happen when you unselect the row.

VladislavAntonyuk avatar Apr 24 '22 18:04 VladislavAntonyuk

I would extend this question... If the default value is -1, I believe that the control isn't fully initialized yet, so the MAUI framework shouldn't trigger the Converters, Triggers, etc. I'm curious in which scenarios this happens.

@emorell96

Could you attach a small repro?

There is a link to a repro in the original post

bijington avatar Apr 24 '22 19:04 bijington

Perhaps we allow the user to return the default value of their specific enum if the incoming value is outside of the acceptable range of values for that enum. Similar to @VladislavAntonyuk s idea but instead of supplying the DefaultValue could the user just state that they wish to ReturnDefaultValueWhenOutsideOfEnumBounds (far better name required).

I don't like the idea of returning null from the converter. That is because while it may work I suspect that is because the binding is failing to convert null to the enum and just not reporting the error and I don't think we should rely on such behaviour.

bijington avatar Apr 25 '22 14:04 bijington

@bijington Do you suggest to return -1 if ReturnDefaultValueWhenOutsideOfEnumBounds is true?

VladislavAntonyuk avatar Apr 25 '22 17:04 VladislavAntonyuk

The thing that worries me is that this happens only when MAUI is a weird state when the Picker has not loaded, I think. It happened when I switched between tabs on my app.

So what worries me is say that you have an initial value for the enum that you are trying to display in the picker, and then this weird state happens, the binding works and gives the default value to the view model value bound to this picker, and then when it loads, instead of showing the value the user actually had, the value is changed to the default value.

Is this possible?

emorell96 avatar Apr 25 '22 17:04 emorell96

That's a good point! It could be a bug in .NET MAUI that we've uncovered.

brminnick avatar Apr 25 '22 19:04 brminnick

@emorell96 Yeah... The behavior that you describes, to me, looks like the SelectedItem should be a CommandMapper and it's implemented as a Mapper... We can check with the team about it

pictos avatar Apr 25 '22 19:04 pictos

@VladislavAntonyuk no I was actually wondering whether we could return the effective value of default for the users enum definition, I am not sure if that is feasible/possible though.

I also then wondered if Binding.DoNothing is something we could return to do as the name suggests. I have asked this in the community Discord to see if anyone has any knowledge of it's correct use https://discord.com/channels/732297728826277939/732297916680765551/968234717541437471

bijington avatar Apr 25 '22 19:04 bijington

I believe it can be closed with 1.3.0 release. You can use SetShouldSuppressExceptionsInConverters

VladislavAntonyuk avatar Sep 15 '22 08:09 VladislavAntonyuk