首页 > 解决方案 > 剃须刀组件中的 C# StateHasChanged() 不强制

问题描述

我正在尝试使用服务器端 blazor。我正在尝试让多个按钮设置/更改在剃须刀组件的标签中播放的 .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();
    }
}

Razor 页面,上面有组件,文件中有 4 个按钮 isw: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 调用的情况下完成这项工作。似乎必须有一种更清洁的方式来做到这一点。

标签: c#blazorblazor-server-side

解决方案


问题不在于StateHasChangeg(),它与html 的Video标签有关:

此方法通常仅在您通过更改元素的 src 属性或通过添加或删除嵌套在媒体元素本身内的元素对媒体元素可用的源集进行动态更改时才有用。load() 将重置元素并重新扫描可用的源,从而使更改生效

这意味着load在更改src属性后强制调用。此时您不能load从 blazor 调用,这意味着您应该通过以下方式调用它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上查看。


推荐阅读