代码之家  ›  专栏  ›  技术社区  ›  vernou

异步更新属性

  •  3
  • vernou  · 技术社区  · 7 年前

    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;
            }
        }
    }
    

    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";
                });
            }
        }
    }
    

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

    但我不能在TodoItem中调用此方法(我不想让TodoItem知道Blazor组件)。

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

    2 回复  |  直到 7 年前
        1
  •  6
  •   Ruben Helsloot Rez    5 年前

    您应该执行以下操作:

    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
  •  4
  •   dani herrera    7 年前

    简单的答案是 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计数器示例,它被修改为:

    @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( () =>
        {
           ...