使用泛型时Picker项选中事件多次触发问题排查
Hey there, let's work through this frustrating issue where your Picker's selection event is firing multiple times when using generics with your Payment Type enum. I've dealt with similar binding quirks in Xamarin apps before, so here are actionable fixes to try out:
1. Stop Re-Subscribing to the Selection Event
One of the most common causes is accidentally subscribing to the event multiple times (e.g., in OnAppearing without unsubscribing in OnDisappearing, or reinitializing your view logic repeatedly). To fix this, always unsubscribe before adding a new subscription:
// Ensure we don't have duplicate subscriptions paymentTypePicker.SelectedIndexChanged -= OnPaymentTypeSelected; paymentTypePicker.SelectedIndexChanged += OnPaymentTypeSelected;
If you're using MVVM and binding commands instead of direct event handlers, double-check that your command isn't being reinitialized multiple times (which can lead to repeated invocations).
2. Cache Your Translated Enum Data
If your friendly name conversion logic runs every time the Picker's ItemsSource is accessed, it might be regenerating the collection repeatedly—triggering unintended selection events. Cache the converted values so they only load once:
private ObservableCollection<string> _paymentTypeOptions; public ObservableCollection<string> PaymentTypeOptions { get { if (_paymentTypeOptions == null) { _paymentTypeOptions = new ObservableCollection<string>( Enum.GetValues(typeof(PaymentType)) .Cast<PaymentType>() .Select(type => ConvertEnumToFriendlyName(type)) // Your conversion method ); } return _paymentTypeOptions; } }
This way, the collection is only created once when first accessed, avoiding unnecessary updates to the Picker.
3. Match SelectedItem Type to Your ItemsSource
If you're binding SelectedItem to an enum value but your ItemsSource contains friendly strings (instead of enum values), the binding system can get confused and trigger multiple updates. Instead, use a wrapper class to pair enum values with their friendly names:
public class EnumDisplayItem<TEnum> where TEnum : Enum { public TEnum Value { get; set; } public string DisplayName { get; set; } } // Initialize your ItemsSource with this wrapper private ObservableCollection<EnumDisplayItem<PaymentType>> _paymentTypeItems; public ObservableCollection<EnumDisplayItem<PaymentType>> PaymentTypeItems { get { if (_paymentTypeItems == null) { _paymentTypeItems = new ObservableCollection<EnumDisplayItem<PaymentType>>( Enum.GetValues(typeof(PaymentType)) .Cast<PaymentType>() .Select(type => new EnumDisplayItem<PaymentType> { Value = type, DisplayName = ConvertEnumToFriendlyName(type) }) ); } return _paymentTypeItems; } }
Then set your Picker's ItemDisplayBinding to DisplayName, and bind SelectedItem to a property of type EnumDisplayItem<PaymentType> (or directly bind SelectedValue to your enum property with SelectedValuePath="Value"). This type matching eliminates binding conflicts that cause repeated events.
4. Clean Up Subscriptions in Page Lifecycle
If you're navigating back to this page frequently, make sure you're cleaning up event subscriptions when the page is disposed. Add this to your code-behind:
protected override void Dispose(bool disposing) { if (disposing) { paymentTypePicker.SelectedIndexChanged -= OnPaymentTypeSelected; } base.Dispose(disposing); }
This prevents old page instances from lingering and firing events when they shouldn't.
内容的提问来源于stack exchange,提问作者Bodungus

