[Blazor]属性值在对象内部被修改时,数据绑定无效

huangapple go评论75阅读模式
英文:

[Blazor]Data binding is invalid when property values are modified inside an object

问题

I bind the name of Student to the input Tag.

If I change the value in the input tag, the data bind is OK, but when I use the "start" button to invoke student.start() to change the name, it does not work as expected, the value of the input does not change.

Did I do something wrong?

razor component:

@page "/data-bind"

@using blazor_winform_sample.Entity;

<h3>data bind test</h3>

<div>
    <div>
        <button @onclick="Start">go!</button>
        <label>@toast</label>
    </div>

    <input type="text" readonly @bind="Stu.Name" />

    <input type="text" @bind="@Stu.Name" />
    <input type="text" value="@Stu.Name" @onchange="@changeValue" />
</div>

@code {
    private Student Stu { get; set; } = new();

    void changeValue(ChangeEventArgs e)
    {
        Stu.Name = "haha" + e?.Value?.ToString();
    }
    private string getName()
    {
        return Stu.Name;
    }

    private string toast = "";
    private void Start()
    {
        Stu.start();
        toast = "start button clicked!";
    }
}

class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace blazor_winform_sample.Entity
{
    public class Student
    {
        private string _name = "";
        public string Name { get { return _name; } set { _name = value; } }

        public Student() { }

        public void start()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    _name = new Random().Next() + "";
                    Thread.Sleep(500);
                }
            });
        }
    }
}

I tried using INotifyPropertyChanged to notify, but it did not work.

英文:

I bind the name of Student to the input Tag.

If i change the value in the input tag, the data bind is OK, but when i use the "start" button to invoke student.start() to change the name, it not work as expected, the value of input not change.

Did I do something wrong?

razor component:

@page &quot;/data-bind&quot;

@using blazor_winform_sample.Entity;

&lt;h3&gt;data bind test&lt;/h3&gt;

&lt;div&gt;
    &lt;div&gt;
        &lt;button @onclick=&quot;Start&quot;&gt;go!&lt;/button&gt;
        &lt;label&gt;@toast&lt;/label&gt;
    &lt;/div&gt;

    &lt;input type=&quot;text&quot; readonly @bind=&quot;Stu.Name&quot; /&gt;

    &lt;input type=&quot;text&quot; @bind=&quot;@Stu.Name&quot; /&gt;
    &lt;input type=&quot;text&quot; value=&quot;@Stu.Name&quot; @onchange=&quot;@changeValue&quot; /&gt;
&lt;/div&gt;

@code {
    private Student Stu{ get; set; } = new();

    void changeValue(ChangeEventArgs e)
    {
        Stu.Name = &quot;haha&quot; + e?.Value?.ToString();
    }
    private string getName()
    {
        return Stu.Name;
    }

    private string toast = &quot;&quot;;
    private void Start()
    {
        Stu.start();
        toast = &quot;start button clicked!&quot;;
    }
}

class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace blazor_winform_sample.Entity
{
    public class Student
    {
        private string _name = &quot;&quot;;
        public string Name { get { return _name; } set { _name = value; } }

        public Student() { }

        public void start()
        {
            Task.Run(() =&gt;
            {
                while (true)
                {
                    _name = new Random().Next() + &quot;&quot;;
                    Thread.Sleep(500);
                }
            });
        }
    }
}

I tried use INotifyPropertyChanged to notify, but it not works.

答案1

得分: 2

抱歉,以下是代码的翻译部分:

抱歉,但这段代码不好!它会阻塞线程:在WASM中,它将阻塞应用程序。

您需要实现一个定时器和一个事件,如下所示:

使用 System.Timers 命名空间:

public class Student : IDisposable
{
    private System.Timers.Timer aTimer;
    private string _name = "";
    public event EventHandler? NameUpdated;
    public string Name { get { return _name; } set { _name = value; } }

    public Student()
    {
        aTimer = new System.Timers.Timer(1000);
        // 钩住计时器的Elapsed事件。
        aTimer.Elapsed += this.OnTimedEvent;
    }

    public void start()
    {
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
    }

    private void OnTimedEvent(Object? source, ElapsedEventArgs e)
    {
        _name = new Random().Next() + "";
        this.NameUpdated?.Invoke(null, EventArgs.Empty);
    }

    public void Dispose()
    {
        aTimer.Elapsed -= this.OnTimedEvent;
        aTimer.Dispose();
    }
}

然后,您的页面如下所示:

  1. 钩住事件监听器以在更改事件发生时更新UI。
  2. 实现 IDisposable 以在组件由渲染器本身处置时清理资源。
@implements IDisposable

@page "/"

<PageTitle>Index</PageTitle>

<h3>数据绑定测试</h3>

<div>
    <div>
        <button @onclick="Start">开始!</button>
        <label>@toast</label>
    </div>

    <input type="text" readonly @bind="Stu.Name" />

    <input type="text" @bind="Stu.Name" />
    <input type="text" value="Stu.Name" @onchange="changeValue" />
</div>

@code {
    private Student Stu { get; set; } = new();

    protected override void OnInitialized()
        => Stu.NameUpdated += OnNameUpdated;

    void changeValue(ChangeEventArgs e)
    {
        Stu.Name = "haha" + e?.Value?.ToString();
    }

    private string getName()
    {
        return Stu.Name;
    }

    private string toast = "";

    private void Start()
    {
        Stu.start();
    }

    private void OnNameUpdated(object? sender, EventArgs e)
        => this.InvokeAsync(StateHasChanged);

    public void Dispose()
    {
        Stu.NameUpdated -= OnNameUpdated;
        Stu.Dispose();
    }
}
英文:

Apologies but :

            Task.Run(() =&gt;
            {
                while (true)
                {
                    _name = new Random().Next() + &quot;&quot;;
                    Thread.Sleep(500);
                }
            });

is not nice code! It blocks the thread: in WASM it will block the application.

You need to implement a timer and an event like this:

using System.Timers;

public class Student : IDisposable
{
    private System.Timers.Timer aTimer;
    private string _name = &quot;&quot;;
    public event EventHandler? NameUpdated;
    public string Name { get { return _name; } set { _name = value; } }

    public Student()
    {
        aTimer = new System.Timers.Timer(1000);
        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += this.OnTimedEvent;
    }

    public void start()
    {
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
    }

    private void OnTimedEvent(Object? source, ElapsedEventArgs e)
    {
        _name = new Random().Next() + &quot;&quot;;
        this.NameUpdated?.Invoke(null, EventArgs.Empty);
    }

    public void Dispose()
    {
        aTimer.Elapsed -= this.OnTimedEvent;
        aTimer.Dispose();
    }
}

And then your page looks like this.

  1. Hooks up a listener to the event to update the UI when the change event occurs.
  2. Implements IDisposable to clean up resources when the component is itself disposed by the Renderer.
@implements IDisposable

@page &quot;/&quot;

&lt;PageTitle&gt;Index&lt;/PageTitle&gt;

&lt;h3&gt;data bind test&lt;/h3&gt;

&lt;div&gt;
    &lt;div&gt;
        &lt;button @onclick=&quot;Start&quot;&gt;go!&lt;/button&gt;
        &lt;label&gt;@toast&lt;/label&gt;
    &lt;/div&gt;

    &lt;input type=&quot;text&quot; readonly @bind=&quot;Stu.Name&quot; /&gt;

    &lt;input type=&quot;text&quot; @bind=&quot;@Stu.Name&quot; /&gt;
    &lt;input type=&quot;text&quot; value=&quot;@Stu.Name&quot; @onchange=&quot;@changeValue&quot; /&gt;
&lt;/div&gt;

@code {
    private Student Stu { get; set; } = new();

    protected override void OnInitialized()
        =&gt; Stu.NameUpdated += OnNameUpdated;

    void changeValue(ChangeEventArgs e)
    {
        Stu.Name = &quot;haha&quot; + e?.Value?.ToString();
    }

    private string getName()
    {
        return Stu.Name;
    }

    private string toast = &quot;&quot;;

    private void Start()
    {
        Stu.start();
    }

    private void OnNameUpdated(object? sender, EventArgs e)
        =&gt; this.InvokeAsync(StateHasChanged);

    public void Dispose()
    {
        Stu.NameUpdated -= OnNameUpdated;
        Stu.Dispose();
        }

}

huangapple
  • 本文由 发表于 2023年3月4日 00:55:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75629858.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定