调用函数后 Blazor 列表未更新

Blazor list not updating after calling functions on it

我正在 blazor web-assembly (.NET 6) 中使用视频播放器开发网页。此 blazor 网页使用 Url 的列表,该列表未正确更新。

一般页面逻辑:该页面创建了一个 IList Videos 的自声明 class ExcerciseVideo。此 IList 应在初始化后更改,具体取决于两个函数的用户输入。

  1. RepeatExercises:此函数在按下按钮并重复特定视频指定次数后调用。这是必要的,因为必须重复几个视频。我想通过使用播放列表来执行此操作,而不是循环播放视频。

  2. ModifyUrl:此函数在按下按钮后调用,应该只更改具有真正双面属性的视频。应将第一个视频的变量 currentUrl 设置为 Url1(当 sidePlayNext == "left" 时),将第二个相同的视频设置为 Url2(当 sidePlayNext == "对)。

我已经尽可能地简化了代码。

 @page "/"
@inject IJSRuntime theJavaScriptEngine;

<!-- Buttons for interaction -->
<button @onclick="StartVideo">Start video</button>
<button @onclick="RepeatExcercises">Repeat Excercises</button>
<button @onclick="ModifyUrl"> Modify Url (of Two Sided Videos)</button>

<!-- Video Element -->
 <div class="align-content-center">
    <video id="videoTagId" autoplay width="1080" height="720"  @onended="NextVideo">
        <source id="videoSourceId" src="@Videos[selected_video_id].CurrentUrl" type="video/mp4"/>
    </video>
</div>

<!-- Developer output -->
@foreach(var v in Videos)
{   
     <li><code>Name: </code>@v.Name</li>
     <li><code>Video Current URl</code>@v.CurrentUrl</li>
     <li><code>Video URl 1</code>@v.Url1</li>
    <li><code>Video URL 2</code>@v.Url2</li>
    <li><code>Two Sided</code>@v.TwoSided</li>
    <li>...</li>
}

@code
{
    public int selected_video_id { get; set; } = 0;
    public IList<ExcerciseVideo>? Videos; // The list we use to store the Videos
    public int Repetitions { get; set; } = 2; // we want each exercise two times
    public string sidePlayNext {get; set; } = "left"; 

    public class ExcerciseVideo
    {
        public string Name { get; set; }
        public string CurrentUrl { get; set; }
        public string Url1 { get; set; } 
        public string Url2{ get; set; } // right hand side of each excercise
        public bool TwoSided { get; set; }
    }

    protected override void OnInitialized()
    {
        Videos = new List<ExcerciseVideo>()
            {
                   new ExcerciseVideo {   
                                Name="Excercise A",
                                CurrentUrl = "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4",
                                Url1="https://backtrainingapp.blob.core.windows.net/backtrainingvideos/20220220_184806[1].mp4",
                                Url2="https://backtrainingapp.blob.core.windows.net/backtrainingvideos/20220220_184806[1].mp4",
                                TwoSided=false},
                  new ExcerciseVideo {   
                                Name="Excercise B",
                                CurrentUrl = "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4",
                                Url1="https://backtrainingapp.blob.core.windows.net/backtrainingvideos/20220220_184632[1].mp4",
                                Url2="https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4",
                                TwoSided=true}

            };

    }

    public void RepeatExcercises()
    {
        // obtain values of the Video List
        int old_video_count = Videos.Count;
        int my_index = 0; 

        // Create a copy of the Video List
        IList<ExcerciseVideo> originalVideos = new List<ExcerciseVideo>(Videos);
        Videos.Clear(); // Clear the list --> we need a clean list for item insertion (in order to not have old items included) 

        // we loop over the list to repeat Videos
        // and insert them
        for (int l = 0; l < old_video_count; l++)
        {
            for (int repeats = 0; repeats < Repetitions; repeats++)
            {
                Videos.Insert(my_index, originalVideos[l]);
                my_index++; // increment the index
            }
        }
        
        StateHasChanged(); // Make sure that the changes are updated             
    }

    // Modify the Url of twoSided Videos
    public void ModifyUrl()
    {

        for (int m = 0; m < Videos.Count; m++)
        {                    
            // check whether a video is twosided
            if (Videos[m].TwoSided == true)
            {

                // check whether left side should be played
                // set Url1 in this case as value
                if (sidePlayNext == "left")
                {
                    Videos[m].CurrentUrl = Videos[m].Url1;
                    Console.WriteLine(sidePlayNext);
                    Console.WriteLine(Videos[m].CurrentUrl);
                    sidePlayNext = "right";
                }

                // check whether right side should be played
                // set Url2 in this case as value
                else if (sidePlayNext == "right")
                {
                    Videos[m].CurrentUrl = Videos[m].Url2;
                    Console.WriteLine(sidePlayNext);
                    Console.WriteLine(Videos[m].CurrentUrl);
                    sidePlayNext = "left";
                }

            }

            // All other cases in which no two sided videos are present
            // --> Current URl should correspond to Url1
            else if (Videos[m].TwoSided == false)
            {
                Videos[m].CurrentUrl = Videos[m].Url1;
                Console.WriteLine("No Direction");
                Console.WriteLine(Videos[m].CurrentUrl);
            }
        }

        StateHasChanged();          
    }

    protected void StartVideo()
    {
        selected_video_id = 0;
        theJavaScriptEngine.InvokeVoidAsync("loadVideo");
    }

    protected void NextVideo()
    {
        selected_video_id = selected_video_id  + 1;
        theJavaScriptEngine.InvokeVoidAsync("loadVideo");
    }

}

测试和遇到的问题(另请参阅 blazor fiddle:https://blazorfiddle.com/s/3ltiwlv3):

我已经在控制台应用程序中测试了“RepeatExcercises”和“ModifyUrl”功能,它们在那里运行良好,并按预期更新了“视频”列表。 最终,我还想更新 VideoPlayer 的 src 属性。我已经尝试使用 blazor 绑定,但也了解到在已经加载时重置视频源很困难(尤其是Url 在列表的指定索引上......) - 我该怎么做?

<!-- Video Element -->
 <div class="align-content-center">
    <video id="videoTagId" autoplay width="1080" height="720"  @onended="NextVideo">
        <source id="videoSourceId" src="@Videos[selected_video_id].CurrentUrl" type="video/mp4"/>
    </video>
</div>

我已经阅读了所有可以在网上找到的类似问题,但现在完全卡住了。非常感谢帮助。

致以最诚挚的问候,谢谢 最大值

Blazor 运行良好。

Q1:更新url

问题出在您的代码上。当您按 'Repeat Exercises' 时,您将插入 ExcerciseVideo Excercise B 的两倍。请注意,您是否只有 Excercise B 的一个实例在列表中插入两次(同一实例对象在列表中两次)。

当您遍历列表时,您发现 Excercise B 两次:

  A
  A
  B
  B  <--- // Is the same ExcerciseVideo instance as previous

然后,在第一个 B 上,您将 url 更改为某个值,然后在第二个 B(与之前的 B 相同)上,您将 url.

改回

要更正您的拼写错误,只需将函数更改为:

public void RepeatExcercises()
{
    // obtain values of the Video List
    int old_video_count = Videos.Count;
    int my_index = 0; 

    // Create a copy of the Video List
    IList<ExcerciseVideo> originalVideos = new List<ExcerciseVideo>(Videos);
    Videos.Clear(); // Clear the list 

    // we loop over the list to repeat Videos
    // and insert them
    for (int l = 0; l < old_video_count; l++)
    {
        for (int repeats = 0; repeats < Repetitions; repeats++)
        {

            var new_video =  new ExcerciseVideo {   // <-- Important part
                            Name=originalVideos[l].Name,
                            CurrentUrl = originalVideos[l].CurrentUrl,
                            Url1=originalVideos[l].Url1,
                            Url2=originalVideos[l].Url2,
                            TwoSided=originalVideos[l].TwoSided};

            Videos.Insert(my_index, new_video);
            my_index++; // increment the index
        }
    }
    
    StateHasChanged(); // Make sure that the changes are updated             
}

Q2:更新视频src

关于您问题的第二部分,更新 src 属性,完整解释如下: