A vkontakte chat is being developed that supports media attachments. A reversed ListView was written that supports data virtualization and uses the ISupportIncrementalLoading interface. Receiving messages occurs over the network from api vkontakte. The message template contains a control that deals with the creation of media attachments (documents, photos, videos, products, etc.).

The problem is this: When a message first appears, attachments, if any, are displayed well. However, if you scroll further or go into a conversation with another person, then these same attachments may appear in messages in which they should not be. What can this happen? I sin on this very virtualization. If you use direct access data virtualization, will the problem disappear? The same error occurs when building posts on the wall. Those. In the new elements appear pieces of previously viewed records.

Code

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

// what creates attachments.

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

2 answers 2

As I already wrote, it's all about virtualization. The best solution found at the moment is the forced cleaning of the template panel containing all attachments. This is done by calling Children.Clear (), after which the panel is filled with new elements. Well, yes, all this needs to be done asynchronously through

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

otherwise strong brakes occur.

    When checking data in

     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(); // Вот тут все и дублируется })); 

    Remove the check and everything will work correctly. Or try not to call ReBuild() in OnApplyTemplate()

    • It does not help. The fact is that at this very moment ReBuild is not called, i.e. everything works out exactly as I need. I played with the debugger for several hours, when those pieces from other templates appear, my dependency property and OnApplyTemplate do not participate in any way, and this check was added in the hope that everything would be fixed, but not destiny, apparently - Arthur
    • I do not leave the feeling that it appears when re-using the container and calculating the height of the element. I wanted to cancel virtualization, but unfortunately StackPanel doesn't have a ItemsUpdatingScrollMode property (it needs a normal list tied to the bottom of the window) - Arthur
    • @Arthur Attach an image, how it is duplicated is not entirely clear. - LLENN
    • pieces of elements from previous controls appeared that were unloaded as you scrolled. I was right, this is due to the virtualization and reuse of already finished containers. Found a solution to the problem, but so far not the best - Arthur