首页 > 解决方案 > 在 xamarin 表单中加载页面后,HTML 标签文本不会呈现

问题描述

我们在 xamarin 表单应用程序中使用Xam.Plugin.HtmlLabel插件。当我们在构造函数中设置html字符串时,html标签在ios中正确加载。但是我们在方法中分配了相同的标签并在构造函数中调用了该方法,它没有在 iOS 中加载,而在 android 中它工作正常。问题重现的代码片段如下所述。此问题仅在 iOS 中发生。

HTMLPage.xaml

    <ContentPage.Content>
        <Grid>
            <ScrollView
                Padding="24"
                HorizontalScrollBarVisibility="Never"
                VerticalScrollBarVisibility="Never">
                <htmlLabel:HtmlLabel
                    Text="{Binding HTMLDescription}"
                    LinkColor="{StaticResource LinkColor}"
                    TextColor="{StaticResource PriTextColor}" />
            </ScrollView>
        </Grid>
    </ContentPage.Content>

HTMLPage.xaml.cs

    private string htmlDescription;
    public string HTMLDescription
    {
        get { return htmlDescription; }
        set { htmlDescription = value; OnPropertyChanged(); }
    }

    public HTMLPage(string Description)
    {
        InitializeComponent();
        GetHTML(Description);
        BindingContext = this;
    }

    private async void GetHTML(string description)
    {
        await Task.Delay(2000); //This delay is for getting the data from server.
        HTMLDescription = description;
    }

标签: htmlxamarin.formsxamarin.ios

解决方案


在任何代码中new HTMLPage("this is some html"),您都在 UI 线程上吗?

如果不在 UI 线程上,那么这就是您的问题 - 在 UI 线程之外处理 UI 元素是有问题的。

如果在 UI 线程上运行,那么您会遇到不同的问题:构造函数是“阻塞”操作 - 在构造函数内部调用的代码上进行异步/等待是没有好处的;UI 线程被阻塞,直到构造函数返回!一般来说,在那里做任何冗长的事情都是个坏主意。最坏的情况是,Web 查询可能会延迟到超时。


相反,尝试在页面出现后设置 HTMLDescription:

// Hold it until used.
string Description;

public HTMLPage(string description)
{
    this.Description = description;
    ...
}

protected override void OnAppearing()
{
    base.OnAppearing();

    // Move to background, so OnAppearing can return.
    Task.Run(() => {
        // Potentially long operation.
        var html = GetHTML(Description);
        // Move to UI thread, before touching any UI element.
        Device.BeginInvokeOnMainThread(() => {
            HTMLDescription = html;
        }
    }
}

private string GetHTML(string description)
{
    Task.Delay(2000); //This delay is for getting the data from server.
    return description;
}

注意:我已经从这个版本的 GetHTML 中删除了 async/await,因为它只在后台线程上调用。如果需要,您可以将它们放回原处。


当然,这样做的缺点是页面最初出现时没有该标签。如果您不希望这样,那么您需要GetHTML(...)在调用构造函数之前改为。

所以你的代码(在你不显示的地方)会是这样的:

var html = GetHTML(...);
new HTMLPage(html);

因此,您回到了有效的原始案例,在构造函数中您已经有了 html 字符串,所以可以简单地做

HTMLDescription = description;

这就引出了一个问题:你为什么一开始不这样做?为什么将调用 GetHtML 放在构造函数中?


推荐阅读