I have create a custom renderer for label that show the text in html format.
This is the iOS's code:
[assembly: ExportRenderer(typeof(LabelHtmlView), typeof(LabelHtmlCustomRenderer))]
namespace SgatMobileV2.iOS {
public class LabelHtmlCustomRenderer : LabelRenderer {
protected override void OnElementChanged(ElementChangedEventArgs<Label> e) {
base.OnElementChanged(e);
var View = (LabelHtmlView)Element;
if (View == null) return;
var Attribute = new NSAttributedStringDocumentAttributes();
var NsError = new NSError();
Attribute.DocumentType = NSDocumentType.HTML;
View.Text = string.IsNullOrEmpty(View.Text) ? string.Empty : View.Text;
Control.AttributedText = new NSAttributedString(View.Text, Attribute, ref NsError);
}
}
}
Android code:
[assembly: ExportRenderer(typeof(LabelHtmlView), typeof(LabelHtmlCustomRenderer))]
namespace SgatMobileV2.Droid.CustomRenderer {
public class LabelHtmlCustomRenderer : LabelRenderer {
public LabelHtmlCustomRenderer(Context context)
: base(context) {
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e) {
base.OnElementChanged(e);
var View = (LabelHtmlView)Element;
if (View == null) return;
Control.SetText(Html.FromHtml(View.Text.ToString(), FromHtmlOptions.ModeLegacy), TextView.BufferType.Spannable);
}
}
}
I use, for example, the control in XAML in this way:
<view:LabelHtmlView Text="{Binding WoDett.NotaTestata}" Grid.Row="0" Grid.Column="1" HeightRequest="200"/>
where WoDett
is a complex object and NotaTestata
is a string that contains HTML markup.
I have debugged the code and the OnElementChanged
is called before I set the WoDett
object, so the NotaTestata
is null
, so the label in XAML appears empty.
This behavior is the same on iOS and Android.
I have others custom renderer and they work properly with similar logic, but this label don't.
How can I solve this?
EDIT:
This is the NotaTestata
property in the object class:
private string _NotaTestata = string.Empty;
public string NotaTestata {
get { return _NotaTestata; }
set {
_NotaTestata = value;
OnPropertyChanged(nameof(NotaTestata));
}
}
EDIT 2:
The same custom label inside a ListView
, works fine.
<ListView x:Name="ListaRigheWo" CachingStrategy="RetainElement" HasUnevenRows="True" SeparatorVisibility="Default" ItemsSource="{Binding ListaWORighe}">
where ListaWORighe
is defined in this way:
public ObservableCollection<WorkOrderDettaglioListaRighe> ListaWORighe {
get {
ObservableCollection<WorkOrderDettaglioListaRighe> Lista = null;
if (WoDett.ListaWORighe != null) {
Lista = OrdinamentoRigheWo(WoDett.ListaWORighe);
}
return Lista;
}
set {
WoDett.ListaWORighe = new List<WorkOrderDettaglioListaRighe>(value);
RaisePropertyChanged(() => ListaWORighe);
}
}
and the custom label is used like this:
<view:LabelHtmlView Text="{Binding DescrizioneIntervento}" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="4" Style="{StaticResource LblValore}" />
EDIT 3:
Following the suggest of user @sme, I have modify the renderers like this, adding the override of OnElementPropertyChanged method:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Label.TextProperty.PropertyName) {
UpdateText();
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e) {
base.OnElementChanged(e);
UpdateText();
}
private void UpdateText() {
var View = (LabelHtmlView)Element;
if (View == null) return;
var Attribute = new NSAttributedStringDocumentAttributes();
var NsError = new NSError();
Attribute.DocumentType = NSDocumentType.HTML;
View.Text = string.IsNullOrEmpty(View.Text) ? string.Empty : View.Text;
Control.AttributedText = new NSAttributedString(View.Text, Attribute, ref NsError);
}