剃须刀组件中的 C# StateHasChanged() 不会强制 <video> 标记为 load/change mp4 播放,仅使用 javascript 似乎有效

C# StateHasChanged() in a razor component does not force <video> tag to load/change the mp4 playing, only using javascript seems to work

我正在试验服务器端 blazor。我正在尝试让多个按钮 set/change 在 razor 组件的标签中播放 .mp4 文件。我发现完成这项工作的唯一方法是通过 IJSRuntime:InvokeVoidAsync() 从我的剃刀组件中的 OnParametersSet() 调用 javascript 函数。 javascript 函数位于 _Host.cshtml 中。对于本应是一个简单的问题,这似乎是一个相当丑陋的解决方案。

我试过在 OnClick 按钮函数中使用 StateHasChanged()。当我查看 chrome 中的 html 渲染时,h1-header 标签和源 src="NewFile" 显示更新,单击按钮时 h1 标签在页面上正确更改,但未加载新视频。我的猜测是这与在自己的线程上播放的视频有关,或者视频标签本身没有改变。我只是不明白如何通过 razor/c#.

完成此操作

由于构建错误,Javascript 代码已添加到文件:_Html.cshtml

  <script>
        function loadVideo (strNewVideo)
        {
            document.getElementById('videoSourceId').src = strNewVideo;
            document.getElementById("videoTagId").load();
        }
    </script>

播放视频的简单组件... 文件:VideoPlayer.razor

@inject IJSRuntime theJavaScriptEngine;

<div class="align-content-center">
    <h1>@this.m_strRenderMe</h1>
    <video id="videoTagId" autoplay width="1080" height="720">
        <source id="videoSourceId" src=@this.m_strRenderMe type="video/mp4" />
    </video>
</div>

@code {
    ElementReference theVideoTag;

    [Parameter]
    public string strVideoFilePath { get; set; }

    private string m_strRenderMe;

    protected override void OnParametersSet()
    {
        this.m_strRenderMe = this.strVideoFilePath;

        theJavaScriptEngine.InvokeVoidAsync("loadVideo", this.m_strRenderMe);

        this.StateHasChanged();
    }
}

包含上面组件和 4 个按钮的 Razor 页面 文件:Counter.razor

@page "/counter"

@using UseBlazorToReadPowerPoint.Classes

@inject CPersistantAppState  thePersistantAppState


<VideoPlayer strVideoFilePath=@thePersistantAppState.m_strVideoPath></VideoPlayer>

<button class="btn btn-primary" @onclick="PlayVideo_1">Video 1</button>
<button class="btn btn-primary" @onclick="PlayVideo_2">Video 2</button>
<button class="btn btn-primary" @onclick="PlayVideo_3">Video 3</button>
<button class="btn btn-primary" @onclick="PlayVideo_4">Video 4</button>

@code {

    void PlayVideo_1()
        {
        thePersistantAppState.m_strVideoPath = "videos/Video-1.mp4";
        }

    void PlayVideo_2()
    {
        thePersistantAppState.m_strVideoPath = "videos/Video-2.mp4";
    }

    void PlayVideo_3()
    {
        thePersistantAppState.m_strVideoPath = "videos/Video-3.mp4";
    }

    void PlayVideo_4()
    {
        thePersistantAppState.m_strVideoPath = "videos/Video-4.mp4";
    }

}

保留所选的文件名。 文件:CPersistantAppState.cs

namespace UseBlazorToReadPowerPoint.Classes
{
    public class CPersistantAppState
    {
        public string m_strVideoPath;
    }
}

列出的代码有效。如果没有 javascript 调用,我无法弄清楚如何完成这项工作。似乎必须有一种更简洁的方法来做到这一点。

问题不在于 StateHasChangeg(),而是关于 html's Video tag:

This method is generally only useful when you've made dynamic changes to the set of sources available for the media element, either by changing the element's src attribute or by adding or removing elements nested within the media element itself. load() will reset the element and rescan the available sources, thereby causing the changes to take effect.

表示在改变src属性后强制调用load。你现在不能从 blazor 调用 load,这意味着你应该通过 IJSRuntime:

调用它

Blazor 代码

<div class="align-content-center">
    <h1>@m_strRenderMe[currentVideo]</h1>
    <button @onclick="ChangeVideo">Change video</button>
    <video id="videoTagId" autoplay width="1080" height="720">
        <source id="videoSourceId" src="@m_strRenderMe[currentVideo]" type="video/mp4" />
    </video>
</div>

@code
{
    int currentVideo = 0;
    string[] m_strRenderMe = new string[] {
        "https://.../videoplayback-1.mp4",
        "https://.../videoplayback-2.mp4"
    };
    protected void ChangeVideo()
    {
        currentVideo = (currentVideo + 1) % 2;
        theJavaScriptEngine.InvokeVoidAsync("loadVideo");
    }
}

JS代码

<script>
    function loadVideo ()
    {
        document.getElementById("videoTagId").load();
    }
</script>

BlazorFiddle 查看。