Дублируются данные в шаблонах списка ListView

317
31 июля 2017, 10:46

Разрабатывается чат вконтакте, который поддерживает медиавложения. Был написан обращённый список ListView, поддерживающий виртуализацию данных и использующий интерфейс ISupportIncrementalLoading. Получение сообщений происходит по сети от апи вконтакте. Шаблон сообщения содержит контрол, который занимается созданием медиавложений (документы, фото, виде, товары и т.д.).

Проблема заключается в следующем: При первом появлении сообщения вложения, если они есть, отображаются хорошо. Однако, если скролить дальше или зайти в беседу с другим человеком, то могут появится эти самые вложения в сообщениях, в которых их быть не должно. Из-за чего такое может происходить? Я грешу на эту самую виртуализацию. Если использовать виртуализацию данных прямого доступа, то проблема исчезнет? Такая же самая ошибка встречается и при построении записей на стене. Т.е. в новых элементах появляются куски ранее просмотренных записей.

Код

<DataTemplate x:DataType="models:Message"
              x:Key="InPrivateMessageTemplate">
    <attachments:MessagesAttachmentsController Attachments="{x:Bind Attach}" />
</DataTemplate>

// то, что создаёт вложения.

public class MessagesAttachmentsController : Control
{
    private StackPanel _layouRoot;
    private MediaItemPresenter _mediaItemPresenter; 
    public MessagesAttachmentsController()
    {
        DefaultStyleKey = typeof(MessagesAttachmentsController);
    }
    public MediaItemPresenter MediaItemPresenter => 
        _mediaItemPresenter ?? (_mediaItemPresenter = new MediaItemPresenter()); 
    public List<IAttachment> Attachments
    {
        get => (List<IAttachment>)GetValue(AttachmentsProperty);
        set => SetValue(AttachmentsProperty, value);
    }
    public static readonly DependencyProperty AttachmentsProperty =
        DependencyProperty.Register(nameof(Attachments), typeof(List<IAttachment>), typeof(MessagesAttachmentsController), new PropertyMetadata(null, (s, e) =>
        {
            if (Equals(e.NewValue, e.OldValue) || e.NewValue == null)
            {
                return;
            }
            (s as MessagesAttachmentsController)?.ReBuild();
        }));
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _layouRoot = GetTemplateChild("LayoutRoot") as StackPanel;
        ReBuild();
    }
    private void ReBuild()
    {
        if (_layouRoot == null || Attachments == null)
        {
            return;
        }
        _layouRoot.Children.Clear(); 

        foreach (var item in Attachments)
        {
            switch (item)
            {
                case Core.Entity.Attachments.Sticker sticker:
                    {
                        CreateStiсker(sticker);
                        return;
                    }
                case Core.Entity.Attachments.Link link:
                    {
                        CreateLink(link);
                        return;
                    }
                case IAttachmentPreview ap:
                    {
                        MediaItemPresenter.Attachments.Add(ap);
                        break; 
                    }
                default:
                    break;
            }
        }
        if (_mediaItemPresenter != null)
        {
            _layouRoot.Children.Add(_mediaItemPresenter); 
        }
    } 
    private void CreateStiсker(Core.Entity.Attachments.Sticker sticker)
    {
        var s = new Sticker
        {
            PhotoUrl = sticker.Photo128,
            Size = 128
        }; 
        _layouRoot.Children.Add(s); 
    }
    private void CreateLink(Core.Entity.Attachments.Link link)
    {
        var l = new Link
        {
            PhotoUrl = link.Photo?.Photo604,
            Title = link.Title,
            Description = link.Description,
            Url = link.Url
        };
        _layouRoot.Children.Add(l); 
    }
}
Answer 1

При проверке данных в

public static readonly DependencyProperty AttachmentsProperty =
            DependencyProperty.Register(nameof(Attachments),
            typeof(List<IAttachment>), typeof(MessagesAttachmentsController),
new PropertyMetadata(null, (s, e) =>
{
    if (Equals(e.NewValue, e.OldValue) || e.NewValue == null) // Всегда будет равен false
    {
        return;
    }
    (s as MessagesAttachmentsController)?.ReBuild(); // Вот тут все и дублируется
}));

Удалите проверку и все будет работать корректно. Либо попробуйте не вызывать ReBuild() в OnApplyTemplate()

Answer 2

Как я уже писал, всё дело в виртуализации. Наилучшее решение, которое нашёл на данный момент - принудительная очистка панели темплейта, содержащая все вложения. Делается посредством вызова Children.Clear(), после чего панель заполняется новыми элементами. Ну и да, всё это необходимо делать асинхронно через

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, handler), 

иначе происходят сильные тормоза

READ ALSO
как передать static файл через koa-router

как передать static файл через koa-router

Мне нужно, чтобы переходя на любой роут моего приложения koa всегда передавал файл indexhtml, т

327
draggable jquery etc

draggable jquery etc

имеется ту ду лист, создается заметка, которая в формате li#draggable > p добавляется в ul в колонку PENDINGхочу реализовать drag&drop, чтобы заметки из колонки...

278
прелоадер во время загрузки страницы

прелоадер во время загрузки страницы

Ребят всем добрый вечер! Помогите сделать чтобы прелоадер работал во время загрузки страницы а по середине в процентах показывало процент...

445