Open japarson opened 5 months ago
365951035a
)[!TIP] I'll email you at japarson@microsoft.com when I complete this pull request!
The sandbox appears to be unavailable or down.
I found the following snippets in your repository. I will now analyze these snippets and come up with a plan.
src/Controls/src/Core/Picker/Picker.cs
✓ https://github.com/japarson/maui/commit/0df0b640d416e6f80d995765fbb10e95446c0919 Edit
Modify src/Controls/src/Core/Picker/Picker.cs with contents:
• Modify the `CoerceSelectedIndex` method to check if the `Items` property is not null and contains elements before coercing the value. If `Items` is null or empty, defer the coercion until after the items have been populated.
• Change the implementation to: ```csharp static object CoerceSelectedIndex(BindableObject bindable, object value) { var picker = (Picker)bindable; if (picker.Items == null || !picker.Items.Any()) return value; // Do not coerce if Items are not set yet return ((int)value).Clamp(-1, picker.Items.Count - 1); } ```
• This change ensures that the `SelectedIndex` is not prematurely coerced to -1 when the items list is empty or not set.
--- +++ @@ -232,8 +232,10 @@ static object CoerceSelectedIndex(BindableObject bindable, object value) { - var picker = (Picker)bindable; - return picker.Items == null ? -1 : ((int)value).Clamp(-1, picker.Items.Count - 1); + var picker = (Picker)bindable; + if (picker.Items == null || !picker.Items.Any()) + return value; // Do not coerce if Items are not set yet + return ((int)value).Clamp(-1, picker.Items.Count - 1); } void OnItemDisplayBindingChanged(BindingBase oldValue, BindingBase newValue)
src/Controls/src/Core/Picker/Picker.cs
✓ Edit
Check src/Controls/src/Core/Picker/Picker.cs with contents:
Ran GitHub Actions for 0df0b640d416e6f80d995765fbb10e95446c0919:
src/Controls/src/Xaml/XamlNode.cs
✓ https://github.com/japarson/maui/commit/c84fc59c7670bd08f4687a83dcd05a29c20f6c0f Edit
Modify src/Controls/src/Xaml/XamlNode.cs with contents:
• Introduce logic to defer the setting of `SelectedIndex` until after the `Items` or `ItemsSource` property has been populated. This might involve tracking if the `SelectedIndex` property has been encountered and setting it after the items have been populated.
• Implement a mechanism to store the `SelectedIndex` value when encountered and apply it after the items are populated. This could be done by adding a temporary property or dictionary to store the `SelectedIndex` value and a method to apply it after items are set.
• Example change (pseudocode for illustrative purposes): ```csharp // Inside the method that processes properties if (propertyName == "SelectedIndex") { StoreSelectedIndexForLater(node, value); // Implement this method } else if (propertyName == "Items" || propertyName == "ItemsSource") { SetItems(node, value); ApplyStoredSelectedIndex(node); // Implement this method } else { SetOtherProperty(node, value); } ```
• This modification ensures that `SelectedIndex` is applied after the items have been populated, addressing the issue of the picker control being empty on Android at initial load.
--- +++ @@ -172,6 +172,21 @@ public NameScopeRef NameScopeRef { get; set; } public override void Accept(IXamlNodeVisitor visitor, INode parentNode) + DictionarydeferredProperties = new Dictionary (); + + public void DeferProperty(XmlName propertyName, object value) + { + deferredProperties[propertyName] = value; + } + + public void ApplyDeferredProperties() + { + foreach (var kvp in deferredProperties) + { + Properties[kvp.Key] = (INode)kvp.Value; + } + deferredProperties.Clear(); + } { if (visitor.VisitingMode == TreeVisitingMode.TopDown && !SkipVisitNode(visitor, parentNode)) visitor.Visit(this, parentNode); @@ -210,6 +225,19 @@ { var clone = new ElementNode(XmlType, NamespaceURI, NamespaceResolver, LineNumber, LinePosition) { + if (!SkipChildren(visitor, this, parentNode)) + { + // Check if ItemsSource or Items is being set and apply deferred SelectedIndex if any + if (Properties.ContainsKey(XmlName.xItemsSource) || Properties.ContainsKey(XmlName.xItems)) + { + ApplyDeferredProperties(); + } + + foreach (var node in Properties.Values.ToArray()) + node.Accept(visitor, this); + foreach (var node in CollectionItems.ToArray()) + node.Accept(visitor, this); + } IgnorablePrefixes = IgnorablePrefixes }; foreach (var kvp in Properties)
src/Controls/src/Xaml/XamlNode.cs
✓ Edit
Check src/Controls/src/Xaml/XamlNode.cs with contents:
Ran GitHub Actions for c84fc59c7670bd08f4687a83dcd05a29c20f6c0f:
I have finished reviewing the code for completeness. I did not find errors for sweep/picker_attribute_selectedindex_not_being
.
💡 To recreate the pull request edit the issue title or description. To tweak the pull request, leave a comment on the pull request.Something wrong? Let us know.
This is an automated message generated by Sweep AI.
Description
I have a Picker that is attached to an enum for a "list type" property, with a "SelectedIndex=0" attribute on the picker, which I believe means that I want that index of the enum to be selected first, as a 'default'. This works great on the windows app, but when running on Android, the picker control is empty. Then, I'm able to force something into the control by manually changing the "selected index" in the .xaml from say, 0 to 1, which I think then triggers the event, and updates in the app. But obviously since I think the point of SelectedIndex is to default something in, then, well, it should default something in.
I found a workaround for this by grabbing the picker control in the constructor in the code-behind for the page, and setting it's SelectedIndex property there, which fixes it. But I presume that the xaml property should work without needing to do that.
Steps to Reproduce
Did you find any workaround?
Yes, as described above - "I found a workaround for this by grabbing the picker control in the constructor in the code-behind for the page, and setting it's SelectedIndex property there, which fixes it."
Investigation
Investigated this for a few hours. It seems that in XamlNode.cs the properties of Picker have SelectedIndex above the Binding PickerItems.
It first then iterates into SelectedIndex, eventually it comes in BindableObject.cs in SetValueCore, where property.CoerceValue is executed against the selectedIndex from the xaml (1 in my example). It is coerced to -1 because there are no items yet, and after that it is not loaded from the XamlNode again.
The next property after SelectedIndex is the PickerItems Binding.
I have yet to figure out what determines the order in which properties are listed, so that I can change the behavior. As seen in the screenshot other properties x:name and textColor are applied after the Binding PickerItems.
Files to Investigate
Checklist
- [X] Modify `src/Controls/src/Core/Picker/Picker.cs` ✓ https://github.com/japarson/maui/commit/0df0b640d416e6f80d995765fbb10e95446c0919 [Edit](https://github.com/japarson/maui/edit/sweep/picker_attribute_selectedindex_not_being/src/Controls/src/Core/Picker/Picker.cs#L232-L237) - [X] Running GitHub Actions for `src/Controls/src/Core/Picker/Picker.cs` ✓ [Edit](https://github.com/japarson/maui/edit/sweep/picker_attribute_selectedindex_not_being/src/Controls/src/Core/Picker/Picker.cs#L232-L237) - [X] Modify `src/Controls/src/Xaml/XamlNode.cs` ✓ https://github.com/japarson/maui/commit/c84fc59c7670bd08f4687a83dcd05a29c20f6c0f [Edit](https://github.com/japarson/maui/edit/sweep/picker_attribute_selectedindex_not_being/src/Controls/src/Xaml/XamlNode.cs#L153-L188) - [X] Running GitHub Actions for `src/Controls/src/Xaml/XamlNode.cs` ✓ [Edit](https://github.com/japarson/maui/edit/sweep/picker_attribute_selectedindex_not_being/src/Controls/src/Xaml/XamlNode.cs#L153-L188)