Megabit / Blazorise

Blazorise is a component library built on top of Blazor with support for CSS frameworks like Bootstrap, Tailwind, Bulma, AntDesign, and Material.
https://blazorise.com/
Other
3.27k stars 529 forks source link

FileEdit Progressed event does not update UI #1184

Closed makhin closed 2 years ago

makhin commented 4 years ago

<FileEdit Multiple="false" Changed="@OnChanged" Progressed="@OnProgressed"></FileEdit>

<ProgressBar Value="@PercentageLoad">@PercentageLoad%</ProgressBar>

        public void OnProgressed(FileProgressedEventArgs e)
        {
            Debug.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
            PercentageLoad = (int)e.Percentage;
            this.StateHasChanged();
        }

Progress bar does not refreshing

makhin commented 4 years ago

sorry wrong code

giovannigambino1980 commented 3 years ago

Hi Alexandr, maybe I'm having the same problem with the same code. How did you solve?

<FileEdit Multiple="false" Changed="@OnChanged" Progressed="@OnProgressed"></FileEdit>

<ProgressBar Value="@PercentageLoad">@PercentageLoad%</ProgressBar>

        public void OnProgressed(FileProgressedEventArgs e)
        {
            Debug.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
            PercentageLoad = (int)e.Percentage;
            this.StateHasChanged();
        }

Progress bar does not refreshing

makhin commented 3 years ago

My code which is working now

                <FileEdit Multiple="false" Filter=".zip" Changed="@OnChanged" Progressed="@OnProgressed">
                </FileEdit>

            <Progress Margin="Margin.Is3.FromTop" Size="Size.Large">
                <ProgressBar Value="@PercentageLoad">@PercentageLoad%</ProgressBar>
            </Progress>
        public int PercentageLoad { get; set; }

        public void OnProgressed(FileProgressedEventArgs e)
        {
            PercentageLoad = (int)e.Percentage;
            this.StateHasChanged();
        }
giovannigambino1980 commented 3 years ago

It's very strange.... I'm using the same code but nothing happens. If I write Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}"); before this.StateHasChanged(); I see data in debug console scrolling, but ProgressBar position is frozen.

mmm, thank you anyway

makhin commented 3 years ago

here is project where I used it https://github.com/makhin/BorderCrossing/tree/master/BorderCrossing/Pages UploadFile and UploadFileBase

stsrki commented 3 years ago

@giovannigambino1980 Are you sure you're using the same code as @makhin ?

In your first example, you only have partial code for ProgressBar, while the full example uses Progress and ProgressBar sub-component.

<Progress Margin="Margin.Is3.FromTop" Size="Size.Large">
  <ProgressBar Value="@PercentageLoad">@PercentageLoad%</ProgressBar>
</Progress>
giovannigambino1980 commented 3 years ago

Hi, that's my code:

<FileEdit Filter=".pdf, .doc, .docx" Multiple = "false" Changed="@OnDocSelected" Progressed="@OnProgressed" />

<Progress Margin="Margin.Is3.FromBottom" Size="Size.Medium" >
    <ProgressBar Value="@this.ProgressValue"> @this.ProgressValue %</ProgressBar>
</Progress>
  private void OnProgressed(FileProgressedEventArgs e)
        {
            Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
            this.ProgressValue = (int)e.Percentage;
            this.StateHasChanged();
        }

When running I see Browser's console writing all percetages, but progress bar doesn't work. I don't know if can be useful, the progress bar is inside a

<Modal @ref="modalRef">
....
</Modal>

tnx so much

stsrki commented 3 years ago

@giovannigambino1980 I tried your example in both modal and in a page. And for me, it works just fine.

Here is my copy-paste code based on yours:

<FileEdit Filter=".pdf, .doc, .docx" Multiple="false" Changed="@OnDocSelected" Progressed="@OnProgressed" />

<Progress Margin="Margin.Is3.FromBottom" Size="Size.Medium">
    <ProgressBar Value="@this.ProgressValue"> @this.ProgressValue %</ProgressBar>
</Progress>

@code{
    int ProgressValue;

    async Task OnDocSelected( FileChangedEventArgs e )
    {
        try
        {
            foreach ( var file in e.Files )
            {
                // A stream is going to be the destination stream we're writing to.
                using ( var stream = new System.IO.MemoryStream() )
                {
                    // Here we're telling the FileEdit where to write the upload result
                    await file.WriteToStreamAsync( stream );

                    // Once we reach this line it means the file is fully uploaded.
                    // In this case we're going to offset to the beginning of file
                    // so we can read it.
                    stream.Seek( 0, System.IO.SeekOrigin.Begin );

                    // Use the stream reader to read the content of uploaded file,
                    // in this case we can assume it is a textual file.
                    using ( var reader = new System.IO.StreamReader( stream ) )
                    {
                        var fileContent = await reader.ReadToEndAsync();
                    }
                }
            }
        }
        catch ( Exception exc )
        {
            Console.WriteLine( exc.Message );
        }
        finally
        {
            this.StateHasChanged();
        }
    }

    private void OnProgressed( FileProgressedEventArgs e )
    {
        Console.WriteLine( $"File: {e.File.Name} Progress: {e.Percentage}" );
        this.ProgressValue = (int)e.Percentage;
        this.StateHasChanged();
    }
}
giovannigambino1980 commented 3 years ago

Unbelievable... I created a brand new page and pasted your code and it still doesn't work. So I think the problem is to search somewhere else. Maybe I'm missing some using? If I set "ProgressValue" manually I see progressbar working. Any idea?

giovannigambino1980 commented 3 years ago

I tried to create a new wasm project, setting up blazorise and pasting your code. TestProgressWASM.zip

Can you help me to understand what's wrong? Tnx so much, Giovanni

makhin commented 3 years ago

I will check tomorrow

makhin commented 3 years ago

I tried to create a new wasm project, setting up blazorise and pasting your code. TestProgressWASM.zip

Can you help me to understand what's wrong? Tnx so much, Giovanni

I checked everything code looks good and should work, but there is one difference between your and mine projects. Your is WASM but mine is Server.
So I can only agree with you Blasorise for WASM has problem with Progressed event

@stsrki can you also check this sample, mb I miss somthing?

stsrki commented 3 years ago

I have just tried it in WASM and it works. A little slower, but still works.

makhin commented 3 years ago

Can you check this sample or share your? Thanks

stsrki commented 3 years ago

It's the same code from .zip file

<FileEdit Filter=".pdf, .doc, .docx" Multiple="false" Changed="@OnDocSelected" Progressed="@OnProgressed" />

<Progress Margin="Margin.Is3.FromBottom" Size="Size.Medium">
    <ProgressBar Value="@this.ProgressValue"> @this.ProgressValue %</ProgressBar>
</Progress>

@code{
    int ProgressValue;

    async Task OnDocSelected( FileChangedEventArgs e )
    {
        try
        {
            foreach ( var file in e.Files )
            {
                // A stream is going to be the destination stream we're writing to.
                using ( var stream = new System.IO.MemoryStream() )
                {
                    // Here we're telling the FileEdit where to write the upload result
                    await file.WriteToStreamAsync( stream );

                    // Once we reach this line it means the file is fully uploaded.
                    // In this case we're going to offset to the beginning of file
                    // so we can read it.
                    stream.Seek( 0, System.IO.SeekOrigin.Begin );

                    // Use the stream reader to read the content of uploaded file,
                    // in this case we can assume it is a textual file.
                    using ( var reader = new System.IO.StreamReader( stream ) )
                    {
                        var fileContent = await reader.ReadToEndAsync();
                    }
                }
            }
        }
        catch ( Exception exc )
        {
            Console.WriteLine( exc.Message );
        }
        finally
        {
            this.StateHasChanged();
        }
    }

    private void OnProgressed( FileProgressedEventArgs e )
    {
        Console.WriteLine( $"File: {e.File.Name} Progress: {e.Percentage}" );
        this.ProgressValue = (int)e.Percentage;
        this.StateHasChanged();
    }
}
makhin commented 3 years ago

TestProgressWASM - Microsoft Visual Studio 11 01 2021 17_29_48

https://user-images.githubusercontent.com/1430717/104210314-02161900-5433-11eb-82f0-c4ac1df1cef6.mp4

Does not work for me.

giovannigambino1980 commented 3 years ago

The same behavior for me. No updates during upload, but just a burst at the end. I tried with all browsers, nothing :(

sgesweinFusion commented 3 years ago

I'm also running into this same behavior on WASM/0.9.2/dotnet core 3.1 with similar code (calling StateHasChanged after changing the Progressbar value, etc.)

While Console.WriteLine shows console output on Chrome at regular intervals, there are no visual updates on the page between 0 and 100.

stsrki commented 3 years ago

Yep, the same thing is happening to me also. Sorry guys, I tested with smaller files and it appeared to work just fine.

sgesweinFusion commented 3 years ago

My workaround of the day for this is rewriting OnProgressed as async and having it explicitly yield to other Blazor work (like updating the UI) after calling StateHasChanged:

    async Task OnProgressed(FileProgressedEventArgs e)
    {
        Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
        _progressedPercent = Convert.ToInt32(e.Percentage);
        StateHasChanged();
        await Task.Yield();
    }

That await Task.Yield() to let Blazor do whatever it wants for a while with the UI thread feels somewhat risky, though, and is probably a bad idea outside of Blazor WASM and maybe in other ways. I'd rather see it baked into file.WriteToStreamAsync() at appropriate points if that seems a prudent course, and let Blazorise worry about it!

pangjianxin commented 2 years ago

seems that the problem still there, @sgesweinFusion 's solution is the best for me

David-Moreira commented 2 years ago

Quite a strange behaviour, Have you guys tried await InvokeAsync(StateHasChanged)?

pangjianxin commented 2 years ago

Quite a strange behaviour, Have you guys tried await InvokeAsync(StateHasChanged)?

sure,i tried this but nothing.it worked for you?

David-Moreira commented 2 years ago

So I was doing some testing, when uploading a larger file, the UI does freeze. It's like Windows Forms all over again haha. Let's not forget Blazor WASM is single threaded, but my guess is that we can hope for multi thread in the future.

The proposed solution of Task.Yield does work. But the UI does act a bit slugish.

I also found out that using

await InvokeAsync(StateHasChanged);
await Task.Delay(1);

does work also giving time to the UI thread to catch up and update. The more you increase the delay time the less slugish the UI looks at the cost of upload time.

We'll see if we can do something about it. Have you guys tried using the OpenReadStream API also?

pangjianxin commented 2 years ago

OpenReadStream api seems can not emit a progress event at all???

David-Moreira commented 2 years ago

These should hopefully be fixed/better in the next version with #3745 While working on the new FilePicker component, we've made some improvements to the FileEdit which should address these issues.

stsrki commented 2 years ago

@David-Moreira I think you accidentally referenced the wrong issue :)

David-Moreira commented 2 years ago

haha right! Similar numbers, thanks. Fixed.