I am using this iOS SegmentedControlRenderer on a page.
But when I go to the page this way: Navigation.PushAsync(new CFSPage())
and then click on the back arrow to go to the previous page, the OnElementChanged event in my customer iOS renderer is fired. The result with my renderer is that the following line gives a null reference error:
segmentedControl.TintColor = e.NewElement?.TintColor.ToUIColor();
Can someone please explain what's the purpose of the ? here and also should this line be after or should it be inside the if (e.NewElement != null)
check. Am I correct in saying that the following lines should NOT be executed if there is no NewElement?
segmentedControl.TintColor = e.NewElement?.TintColor.ToUIColor(); SetNativeControl(segmentedControl); SetSelectedSegment();
This renderer as is doesn't have an
protected override void Dispose(bool disposing)
Is that something that's missing?
Renderer
public class SegmentedControlRenderer : ViewRenderer<SegmentedControl, UISegmentedControl> { protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e) { base.OnElementChanged(e); UISegmentedControl segmentedControl = null; if (Control == null) { segmentedControl = new UISegmentedControl(); for (var i = 0; i < e.NewElement.Children.Count; i++) { segmentedControl.InsertSegment(Element.Children[i].Text, i, false); } SetNativeControl(segmentedControl); SetSelectedSegment(); } if (e.OldElement != null) { if (segmentedControl != null) segmentedControl.ValueChanged -= NativeValueChanged; } if (e.NewElement != null) { segmentedControl.ValueChanged += NativeValueChanged; } segmentedControl.TintColor = e.NewElement?.TintColor.ToUIColor(); SetNativeControl(segmentedControl); SetSelectedSegment(); } protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == nameof(SegmentedControl.SelectedSegment)) SetSelectedSegment(); if (e.PropertyName == SegmentedControl.TintColorProperty.PropertyName) SetSegmentTintColor(); } void NativeValueChanged(object sender, EventArgs e) { if (Element is SegmentedControl formsElement) { formsElement.SelectedSegment = (int)Control.SelectedSegment; }; } void SetSegmentTintColor() { if (Element is SegmentedControl formsElement) Control.TintColor = formsElement.TintColor.ToUIColor(); } void SetSelectedSegment() { if (Element is SegmentedControl formsElement) { if (formsElement.SelectedSegment >= 0 && formsElement.SelectedSegment < Control.NumberOfSegments) Control.SelectedSegment = formsElement.SelectedSegment; } } }
2 Answers
Answers 1
The following is an example of how OnElementChanged
in most renderers is structured:
protected override void OnElementChanged(ElementChangedEventArgs<Type> e) { base.OnElementChanged(e); if (e.OldElement != null) { // Unsubscribe from event handlers and cleanup any resources } if (e.NewElement != null) { if (Control == null) { // Instantiate the native control and assign it to the Control property with // the SetNativeControl method } // Configure the control and subscribe to event handlers } }
Please note that Control
might be null when if (e.OldElement != null)
is true and should not normally be recreated in this situation.
See also Xamarin.Forms iOS ButtonRenderer.
Answers 2
The ?. can be found at C# 6.0 docs:
You need to check every access of variables to ensure you are not dereferencing null. The null conditional operator makes those checks much easier and fluid.
Simply replace the member access
.
with?.
In short:
segmentedControl.TintColor = e.NewElement?.TintColor.ToUIColor();
is the same as:
if (e.NewElement != null) { segmentedControl.TintColor = e.NewElement.TintColor.ToUIColor(); }
So yes, you are correct, it should not execute if there is NewElement
.
0 comments:
Post a Comment