Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Razor component list item not updating UI

$
0
0

Beforehand i apologize for any mistakes, as English is not my first language.I'm creating a razor component library to be implemented in an existent .NET 7 Blazor Server application. Basically a simple IMAP e-mail client, I'm using MailKit library.I have used the MailKit documentation example for windows forms, and adjusted to work in razor.It is populating the folders as expected, but when I try to update an MessageInfo item, as an example, changing to flagged or unflagged, I'm trying to udate the UI accordingly, but the changes are only applied on page refresh.

I tried StateHasChanged, InvokeAsync(StateHasChanged), event Action, all without success.This is what i got so far, serviçe:

using BlazorEmailLib.Models;using MailKit;using MailKit.Net.Imap;namespace BlazorEmailLib.Services;public interface IMessageListService{    event EventHandler<MessageSelectedEventArgs>? MessageSelected;    event Action? OnMessagesUpdated;    Task OpenFolderAsync(IMailFolder folder);    void AddMessageSummaries(IMailFolder folder, IEnumerable<IMessageSummary> summaries);    void SelectMessage(MessageInfo messageInfo);    List<MessageInfo> GetMessages();    Task ToggleFlagAsync(MessageInfo messageInfo, MessageFlags flags);}public class MessageListService : IMessageListService{    private static readonly FetchRequest _request = new(MessageSummaryItems.UniqueId | MessageSummaryItems.Envelope | MessageSummaryItems.Flags | MessageSummaryItems.BodyStructure);    private const int _batchSize = 512;    private readonly List<MessageInfo> _messages = new();    private IMailFolder? _folder;    public event EventHandler<MessageSelectedEventArgs>? MessageSelected;    public event Action? OnMessagesUpdated;    public async Task OpenFolderAsync(IMailFolder folder)    {        if (this._folder != null)        {            this._folder.MessageFlagsChanged -= OnMessageFlagsChanged;            this._folder.MessageExpunged -= OnMessageExpunged;            this._folder.CountChanged -= OnCountChanged;        }        folder.MessageFlagsChanged += OnMessageFlagsChanged;        folder.MessageExpunged += OnMessageExpunged;        this._folder = folder;        lock (_messages)        {            _messages.Clear();        }        try        {            if (!folder.IsOpen)                await folder.OpenAsync(FolderAccess.ReadWrite);            if (folder.Count > 0)            {                var summaries = await folder.FetchAsync(0, -1, _request);                AddMessageSummaries(folder, summaries);            }        }        catch (ImapCommandException ex) when (ex.Message.Contains("NO"))        {            Console.WriteLine("Algumas mensagens não existem mais. Atualizando a lista...");            await folder.OpenAsync(FolderAccess.ReadWrite);        }        catch (Exception ex)        {            Console.WriteLine($"Erro inesperado: {ex.Message}");        }        folder.CountChanged += OnCountChanged;    }    public void AddMessageSummaries(IMailFolder folder, IEnumerable<IMessageSummary> summaries)    {        if (folder != this._folder)            return;        foreach (var message in summaries)        {            var info = new MessageInfo(message);            _messages.Add(info);        }        if (_messages.Count < folder.Count)            FetchNewMessages(folder);    }    private void FetchNewMessages(IMailFolder folder)    {        Task.Run(async () =>        {            if (!folder.IsOpen)                await folder.OpenAsync(FolderAccess.ReadWrite);            if (folder.Count > 0)            {                int currentCount;                lock (_messages)                {                    currentCount = _messages.Count;                }                var summaries = await folder.FetchAsync(currentCount, Math.Min(folder.Count - 1, currentCount + _batchSize - 1), _request);                AddMessageSummaries(folder, summaries);            }        });    }    private void OnMessageFlagsChanged(object? sender, MessageFlagsChangedEventArgs e)    {        lock (_messages)        {            if (e.Index < _messages.Count)            {                var info = _messages[e.Index];                info.Flags = e.Flags;            }        }    }    private void OnMessageExpunged(object? sender, MessageEventArgs e)    {        lock (_messages)        {            if (e.Index < _messages.Count)            {                _messages.RemoveAt(e.Index);            }        }    }    private void OnCountChanged(object? sender, EventArgs e)    {        var folder = (IMailFolder)sender!;        FetchNewMessages(folder);    }    public void SelectMessage(MessageInfo messageInfo)    {        if (_folder != null)        {            MessageSelected?.Invoke(this, new MessageSelectedEventArgs(_folder, messageInfo.Summary.UniqueId, messageInfo.Summary.Body));        }    }    public List<MessageInfo> GetMessages()    {        lock (_messages)        {            return new List<MessageInfo>(_messages);        }    }    public async Task ToggleFlagAsync(MessageInfo messageInfo, MessageFlags flags)    {        if (_folder != null)        {            if (messageInfo.Flags.HasFlag(flags))            {                await _folder.RemoveFlagsAsync(messageInfo.Summary.UniqueId, flags, true);            }            else            {                await _folder.AddFlagsAsync(messageInfo.Summary.UniqueId, flags, true);            }            // Notifica que as mensagens mudaram            OnMessagesUpdated?.Invoke();        }    }}public class MessageSelectedEventArgs : EventArgs{    public IMailFolder Folder { get; }    public UniqueId UniqueId { get; }    public BodyPart Body { get; }    public MessageSelectedEventArgs(IMailFolder folder, UniqueId uniqueId, BodyPart body)    {        Folder = folder;        UniqueId = uniqueId;        Body = body;    }}

And the razor component:

@using Microsoft.AspNetCore.Components.Web@using Microsoft.Extensions.Logging@using BlazorEmailLib.Services@using BlazorEmailLib.Helpers@using BlazorEmailLib.Models@using MailKit@using MailKit.Net.Imap;@using MimeKit@inject IImapClientService ImapClientService@inject IMessageListService MessageListService@inject ILogger<MessageListView> Logger@namespace BlazorEmailLib.Components<div>    @if (IsLoading)    {        foreach (var i in Enumerable.Range(0, 10))        {<div class="email-item"><input type="checkbox" class="skeleton" /><div class="email-item-info"><div class="email-item-info__header skeleton" style="height: 20px; margin-bottom: 0.25rem;"></div><div class="email-item-subject skeleton" style="height: 20px;"></div><div class="email-item-details skeleton" style="height: 40px;"></div></div></div>        }    }    else if (_messages != null && _messages.Any())    {        @foreach (var message in _messages)        {<div @key="@message.Summary.UniqueId"                    class="email-item @(message.Flags.HasFlag(MessageFlags.Seen) ? "seen" : "") @(IsCurrent ? "email-item__selected":"")"><input type="checkbox" name="@message.Summary.UniqueId"                        id="@message.Summary.UniqueId" value="@message.Summary.UniqueId"                        checked="@IsSelected"                        @onchange="async (e) => await IsSelectedChanged.InvokeAsync(e.Value != null && (bool)e.Value)" /><div class="email-item-info" @onclick=HandleClick><div class="email-item-info__header"><span class="email-item-info__header-from">@message.Summary.Envelope.From.Mailboxes.FirstOrDefault()!.Address</span><span class="email-item-info__header-datetime">                            @if (message.Summary.Envelope.Date?.Date == DateTimeOffset.Now.Date)                            {                                @message.Summary.Envelope.Date?.DateTime.ToString("HH:mm")                            }                            else                            {                                @message.Summary.Envelope.Date?.DateTime.ToString("dd/MM/yyyy")                            }</span></div><div class="email-item-subject">                        @CommonHelpers.TruncateText(message.Summary.NormalizedSubject)</div><div class="email-item-details"><span>@CommonHelpers.ConvertMessageSize(message.Summary.Size.GetValueOrDefault())</span><span>                        @if (message.Summary.Attachments.Any(a => a.IsAttachment))                        {<i class="fa-solid fa-paperclip"></i>                        }                        @if (message.Summary.Flags != null)                        {                            @if (message.Summary.Flags.Value.HasFlag(MessageFlags.Answered))                            {<i class="fa fa-check"></i>                            }<span @onclick:stopPropagation                                    @onclick="@(async () => await HandleFlagClick(message, MessageFlags.Flagged))"><i class="fa fa-flag icon-button @(message.Flags.HasFlag(MessageFlags.Flagged) ? "text-danger" : "")"></i></span>                        }</span></div></div></div>        }    }    else    {<p>No messages found.</p>    }</div>@code {    [Parameter] public IMailFolder? Folder { get; set; }    private List<MessageInfo>? _messages;    private bool IsLoading { get; set; } = true;    private bool IsCurrent { get; set; }    public bool IsSelected { get; set; }    public EventCallback<bool> IsSelectedChanged { get; set; }    protected override async Task OnParametersSetAsync()    {        if (Folder != null)        {            IsLoading = true;            await MessageListService.OpenFolderAsync(Folder);            _messages = new List<MessageInfo>(MessageListService.GetMessages());            IsLoading = false;        }    }    protected override void OnInitialized()    {        MessageListService.OnMessagesUpdated += async () => await InvokeAsync(StateHasChanged);    }    private async void HandleMessagesUpdated()    {        await InvokeAsync(StateHasChanged);    }    private void SelectMessage(MessageInfo messageInfo)    {        MessageListService.SelectMessage(messageInfo);    }    private async Task HandleClick(MouseEventArgs e)    {    }    private async Task HandleFlagClick(MessageInfo message, MessageFlags flags)    {        await MessageListService.ToggleFlagAsync(message, flags);        // Atualiza o estado do objeto (Blazor só deteta mudanças em propriedades e não referências)        message.Flags = message.Flags.HasFlag(flags)            ? message.Flags & ~flags  // Remove flag            : message.Flags | flags;  // Adiciona flag        // Força o Blazor a redesenhar o componente        await InvokeAsync(StateHasChanged);    }    public void Dispose()    {        MessageListService.OnMessagesUpdated -= HandleMessagesUpdated;    }}

I appreciate any help, thank you in advance.


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>