【问题标题】:Update a property asynchronous异步更新属性
【发布时间】:2019-04-21 04:39:28
【问题描述】:

当我的 ViewModel 的一个属性更新时,其他属性会异步更新。

Todo.cshtml:

@page "/todo"

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" bind="@todo.IsDone" />
            <input bind="@todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" bind="@newTodo"/>
<button onclick="@AddTodo">Add todo</button>

@functions {
    IList<TodoItem> todos = new List<TodoItem>();


    string newTodo;
    void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}

TodoItem.cs:

public class TodoItem
{
    private bool _isDone;

    public string Title { get; set; }
    public bool IsDone
    {
        get => _isDone;
        set
        {
            _isDone = value;
            Task.Run(() =>
            {
                //Simulate work
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
                //Update property
                Title = Title + " - Done";
            });
        }
    }
}

在同步(没有 Task.Run)中,这可以正常工作,但在异步中,UI 不会更新。

我需要解释要使用StateHasChanged() 更新的 UI: https://github.com/aspnet/Blazor/issues/1413

但我不能在 TodoItem 中调用此方法(而且我不希望 TodoItem 知道 Blazor 组件)。

你有更新 UI 的解决方案吗?

【问题讨论】:

  • 为什么不在TodoItem(如IsDoneComplete)中添加一个回调事件/处理程序,类型为Action,以便您的视图注册以便调用StateHasChanged
  • 是的,我认为我的虚拟机需要更新视图或通知视图。

标签: c# .net blazor


【解决方案1】:

您应该执行以下操作:

  1. 在你的类中定义一个动作委托:

     public event Action OnChange;
    
  2. 在这个类中定义一个方法NotifyStateChanged(),如下所示:

     private void NotifyStateChanged() => OnChange?.Invoke();
    

    此方法触发OnChange 事件。您应该在完成它所做的任何任务后从您的逻辑中调用此方法。

  3. 在您的 todo 组件中,将 StateHasChanged 方法添加到您的 TodoItem 类中使用的事件委托中:

     @functions
     {
         protected override void OnInit()
         {
             state.OnChange += StateHasChanged;
         }
     }
    

【讨论】:

    【解决方案2】:

    简单的答案是 “修改你的 var 后只需触发 StateHasChanged();

            Task.Run(() =>
            {
                //Simulate work
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
                //Update property
                Title = Title + " - Done";
                StateHasChanged();
            });
    

    因为你的方法是异步的,所以重写为:

            Task.Run(async () =>  //<--here async
            {
                //Simulate async work
                Task.Run( async () => {
                    await Task.Run( () => {} ); //<--- await
                    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
                });
                //Update property
                Title = Title + " - Done";
                StateHasChanged();
            });
    

    为了避免反模式和编写干净的代码,您的 ModelView 可能有一个公共事件来通知 UI 它已更改,只需将 UI 上的此事件连接到 StateHasChanged();

    我在这里写了修改后的 Blazor Counter 示例:

    @page "/counter"
    
    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" onclick="@IncrementCount">
        Click me @s <!-- here var -->
    </button>
    
    @functions {
        int currentCount = 0;
    
        string s = "";
    
        void IncrementCount()
        {
            currentCount++;
            Task.Run(() =>
                {
                    //Simulate work
                    Task.Run( async () => {
                        await Task.Run( () => {} );
                        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));}
                            );
                    //Update property
                    s = s + " - Done";
                    StateHasChanged();
                });
            }
        }
    }
    

    已编辑

    不再支持从线程调用StateHasChanged。只需更改:

        Task.Run(() =>
        {
            //Simulate work
            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
            //Update property
            Title = Title + " - Done";
            StateHasChanged();
        });
    

        Invoke( () =>
        {
           ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多