Reputation: 33
Visual elements in Xamarin Forms are made visible/invisible by setting their IsVisible property. Changing some properties or data on visual elements can cause the interface to redraw, which can be expensive.
I'm trying to improve performance on my app so I've introduced caching and tried to make some layout simplifications, but I have to make a lot of visual elements visible/invisible and wondered wht the best way would be to optimise this.
Which is the more efficient operation?
var myButton.IsVisible = true;
Or:
if(!myButton.IsVisible) myButton.IsVisible = true;
If Xamarin already checks the state and decides whether to redraw then the second option is redundant and therefore inefficient. If a redraw happens every time the property is set then it will be more efficient. I can't find any documentation to tell me which is the case.
Upvotes: 1
Views: 137
Reputation:
Any good implementation of a DependencyProperty
(or INotifyPropertyChanged
) member should ignore successive set
s if that value
is the same. For that reason let IsVisible
work out what to do rather than place responsiblity on callers.
If Xamarin already checks the state and decides whether to redraw then the second option is redundant and therefore inefficien
That's right. Xamarin, like other XAML-based implemenations, are visually-efficient (unlike WinForms) so setting a visual property is not likely to immediately cause a screen refresh. Additonally, the entire app window is rendered in a single blit to avoid flicker.
In Xamarin, setting button.IsVisible
for example makes it way down to BindableObject.SetValueActual
(Button
has BindableObject
in its inheritance graph) where checks are made for sameness. The new value is only applied if the value is different or if SetValueFlags.RaiseOnEqual
is set.
OnPropertyChanged
and PropertyChanged
are called on different values or if RaiseOnEqual
is set.
Xamarin source code from GitHub: (my comments)
void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
{
object original = context.Value;
bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
if (!silent && (!same || raiseOnEqual))
{
property.PropertyChanging?.Invoke(this, original, value);
OnPropertyChanging(property.PropertyName);
}
if (!same || raiseOnEqual)
{
context.Value = value; // <---------- assignment
}
.
.
.
if (!silent && (!same || raiseOnEqual)) // <------- notifications guard
{
if (binding != null && !currentlyApplying)
{
_applying = true;
binding.Apply(true);
_applying = false;
}
OnPropertyChanged(property.PropertyName);
property.PropertyChanged?.Invoke(this, original, value);
Upvotes: 2