英文:
[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 "/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 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();
}
}
然后,您的页面如下所示:
- 钩住事件监听器以在更改事件发生时更新UI。
- 实现 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(() =>
{
while (true)
{
_name = new Random().Next() + "";
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 = "";
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() + "";
this.NameUpdated?.Invoke(null, EventArgs.Empty);
}
public void Dispose()
{
aTimer.Elapsed -= this.OnTimedEvent;
aTimer.Dispose();
}
}
And then your page looks like this.
- Hooks up a listener to the event to update the UI when the change event occurs.
- Implements IDisposable to clean up resources when the component is itself disposed by the Renderer.
@implements IDisposable
@page "/"
<PageTitle>Index</PageTitle>
<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();
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();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论