我正在尝试创建一个在应用程序运行时添加日志的日志页面。
所需的功能是能够自动滚动到最新(最新)添加的日志。

问题是,当我在observablecollection上使用scrollto函数时,日志记录页面似乎重新加载了整个列表。

这不是问题,但是当列表足够大时,它会导致页面在重绘列表时闪烁。

无论如何,是否将日志语句添加到页面并滚动到页面的最后一个元素而不会导致页面闪烁。

我真的想使用任何解决方案,但必须满足以下要求:


能够在创建/添加日志时实时刷新(经常刷新)
能够自动滚动到页面末尾。
能够干净刷新(没有闪烁或其他类型的问题)。


我的尝试:

我尝试了两种不同的方法来实现此目的。

第一种方法是将“ logstatement”(字符串)的标签添加到
内容页。然后,我将使用lastorDefault()方法在布局中查找最后一个子级(在本例中为stacklayout)
然后滚动到该项目(在本例中为Label())。

我必须使用Device.BeginInvokeOnMainThread将标签添加到主线程(否则它将与程序的其他方面冲突),这会导致滚动功能和此调用之间出现竞争状态,最终在列表足够大时引发异常。
这种方式的第二个问题是,当页面足够大并且我们要添加语句时,它还会出现此闪烁的问题。

我尝试实现它的第二种方法是使用可观察的集合,在该集合中,我向observablecollection添加标签并使用
用来访问标签文本和文本颜色的数据模板。添加标签后,我使用scrollto函数滚动到列表的底部。
当列表较小(小于150个左右)时,此方法很好用,但随后在添加标签(对数声明)时页面闪烁。

我当前的想法是在可观察的集合中仅保留最后50个左右的项目,以便刷新干净
我正在寻找更好的解决方案,但也许不存在。

我已对显示的代码进行了重大修改,因此其中的一些代码没有任何意义,但我尝试在此处保持逻辑纯净。

我现在无法添加可编译代码,但是如果此代码不足,我将创建一个测试项目,请告诉我。

码:

    public LoggingPage()
    {
        InitializeComponent();
        loggingPage.ItemAppearing += EnableAutoScroll;
        DisplayLogsOnScreen(logstatements);
    }

    //adds the logs to the screen
    private void DisplayLogsOnScreen(LogStatement logstatements)
    {
        Label loggingLabel = new Label();


        foreach (typeOfLog tempLogType in differentlogTypes)
        {
            switch (tempLogType)
            {
                case typeOfLog.FIRSTTYPE:
                    Device.BeginInvokeOnMainThread(() => {
                        logObservableCollection.Add(loggingLabel);
                    });
                    break;
                case LogType.SECONDTYPE:
                    Device.BeginInvokeOnMainThread(() => {
                        differentLogObservableCollection.Add(loggingLabel);
                    });
                    break;
                default:
                    break;
            }
        }
    }



   // have to wrap the scrollto events in an itemAppeared event handler
   // otherwise the update to the UI is laggy
   // it still has issues updating the logview this workaround is not perfect

    private void AddAutoScroll(object sender, EventArgs e)
    {
            if (autoScroll)//a button that enables and disables autoscroll
            {
                logListView.ScrollTo(logObservableCollection.LastOrDefault(), ScrollToPosition.End, true);
                logListView.ScrollTo(differentLogObservableCollection.LastOrDefault(), ScrollToPosition.End, true);

            }
    }


Xaml:

<ContentPage Title="logPage">
    <ContentPage.Content>
        <ListView x:Name="loggingPage">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text="{Binding Text}" TextColor="{Binding TextColor}"/>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>
</ContentPage>

最佳答案

这里的问题是ListView的ScrollTo()函数。当我们打电话给:

            logListView.ScrollTo(logObservableCollection.LastOrDefault(), ScrollToPosition.End, true);


ScrollTo函数似乎遍历整个可观察的集合,以找到列表中的最后一项。

我通过创建方法而不是使用此onAppearing事件处理程序来规避此问题。

这是我更新的代码。注意,两者都必须在主线程上调用。

       if (statementObject.Types.Contains(LogType.diffLogType))
        {
            Device.BeginInvokeOnMainThread(() => {
                _incidentLabelListCollection.Add(logStatement);
                if (autoScroll)
                    EnableAutoScroll(logStatement,null);
            });
        }


第二种方法

    private void EnableAutoScroll(Label label, ListView listView)
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            if(logListView.IsVisible)
                logListView.ScrollTo(label, ScrollToPosition.End, false);

        });
    }

09-30 14:07
查看更多