【问题标题】:Custom Label renderer not set binded text自定义标签渲染器未设置绑定文本
【发布时间】:2018-06-23 20:31:45
【问题描述】:

我为标签创建了一个自定义渲染器,以 html 格式显示文本。

这是 iOS 的代码:

   [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);

        }    
    }
}

安卓代码:

[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);
        }

    }
}

例如,我以这种方式使用 XAML 中的控件:

<view:LabelHtmlView Text="{Binding WoDett.NotaTestata}" Grid.Row="0" Grid.Column="1" HeightRequest="200"/>

其中WoDett 是一个复杂对象,NotaTestata 是一个包含 HTML 标记的字符串。

我已经调试了代码,在我设置WoDett对象之前调用了OnElementChanged,所以NotaTestata是null,所以XAML中的标签显示为空。

这种行为在 iOS 和 Android 上是相同的。

我有其他自定义渲染器,它们可以使用类似的逻辑正常工作,但这个标签不能。

我该如何解决这个问题?

编辑:

这是对象类中的NotaTestata 属性:

private string _NotaTestata = string.Empty;
public string NotaTestata {
    get { return _NotaTestata; }
    set {
          _NotaTestata = value;
          OnPropertyChanged(nameof(NotaTestata));
        }
    }

编辑 2:

ListView 中的相同自定义标签可以正常工作。

<ListView x:Name="ListaRigheWo" CachingStrategy="RetainElement" HasUnevenRows="True" SeparatorVisibility="Default" ItemsSource="{Binding ListaWORighe}">

ListaWORighe 是这样定义的:

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);
            }
        }

自定义标签的使用方式如下:

<view:LabelHtmlView Text="{Binding DescrizioneIntervento}" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="4" Style="{StaticResource LblValore}" />

编辑 3:

根据用户@sme 的建议,我已经像这样修改了渲染器,添加了 OnElementPropertyChanged 方法的覆盖:

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);
        }

【问题讨论】:

  • 对于您的 WoDett 对象,NotaTestata 属性是否在 setter 中包含 OnPropertyChanged(nameof(NotaTestata)) 事件处理程序调用?
  • 是的,确实如此。我已经编辑了问题。
  • 你设置BindingContext了吗?我想你是否在绑定方面做错了什么?
  • @Land 是的,我使用具有 AutoWireViewModel 属性的类将视图模型绑定到视图,并且视图上的所有其他绑定属性都可以正常工作。如果我使用普通标签,它会显示 HTML 标记。

标签: c# xamarin binding custom-renderer


【解决方案1】:

您的两个渲染器也应该覆盖OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 方法。 OnElementChanged 在创建新对象时调用,OnElementPropertyChanged 在对象属性发生更改时调用。我建议这样做(在您的 OnElementPropertyChanged() 方法中:

if (e.PropertyName == Label.TextProperty.PropertyName)
{
    // the text was updated
    Control.SetText(...);
}

【讨论】:

  • 我已经编辑了两个渲染器,但仍然无法正常工作。我也编辑了这个问题。
  • @Hikari 你能在OnElementPropertyChanged 方法中设置一个断点,看看TextProperty 是否会改变吗?
  • 它被调用,但不是为TextProperty。我还添加了一个更改 NotaTestata 值的测试按钮,但不调用 OnElementPropertyChanged 方法。
  • @Hikari 标签是否在列表视图中的单元格内?视图模型是什么样的?
  • 标签在 TableView 内。我制作了一个带有视图、viewModel 和渲染器的 zip:ufile.io/22bvt
【解决方案2】:

我已经通过这种方式在 XAML 上添加 Mode=TwoWay 来解决:

<view:LabelHtmlView Text="{Binding WoDett.NotaTestata, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" />

我不知道为什么自定义标签是必需的,而对于“普通”标签则不是,但现在它似乎可以正常工作。

非常感谢!

【讨论】:

  • 在这种情况下,您似乎正在通过设置myCustomLabel.Text = "..."; 更新视图中的文本。这将更新您的视图,但除非您有双向绑定,否则绑定对象的值不会改变。相反,您应该直接更新 View Model 中 WoDett.NotaTestata 值的值,Wodett.NotaTestata = "..."; 双向绑定最适合处理用户对文本框、单选按钮等的输入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
  • 2017-04-19
  • 2017-06-09
  • 2015-03-29
  • 2019-08-01
  • 2022-09-29
相关资源
最近更新 更多