C# Blazor 服务器:使用 INotifyPropertyChanged 显示实时数据
C# Blazor Server: Display live data using INotifyPropertyChanged
我有一个小问题,我尝试在我的 Blazor 服务器项目的页面上显示实时数据。在阅读了几篇文章后,我认为这应该可以通过使用 INotifyPropertyChanged 来实现。不幸的是我对此一窍不通,这是我尝试过的:
我使用 INotifyPropertyChanged 的模型价格(使用 Rider 生成):
public class Price : INotifyPropertyChanged
{
private double _askPrice;
private double _bidPrice;
private double _spread;
public Price(double askPrice, double bidPrice)
{
_askPrice = askPrice;
_bidPrice = bidPrice;
}
public double AskPrice {
get => _askPrice;
set
{
_askPrice = value;
OnPropertyChanged("AskPrice");
OnPropertyChanged("Spread");
}
}
public double BidPrice
{
get => _bidPrice;
set
{
_bidPrice = value;
OnPropertyChanged("BidPrice");
OnPropertyChanged("Spread");
}
}
public double Spread => _askPrice - _bidPrice;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
如何获取实时数据:
public class PriceService
{
public static Price BinancePrice;
public static void StartBinanceStream()
{
var client = new BinanceSocketClient();
// subscribe to updates on the spot API
client.Spot.SubscribeToBookTickerUpdates("BTCEUR", data =>
{
BinancePrice = new Price((double)data.BestAskPrice, (double)data.BestBidPrice);
});
}
}
最后是我的 razorfile 的内容:
<h5>BID: @($"{PriceService.BinancePrice.BidPrice:F2} EUR")</h5>
<h5>ASK: @($"{PriceService.BinancePrice.AskPrice:F2} EUR")</h5>
<h5>Spread: @($"{PriceService.BinancePrice.Spread:F2} EUR")</h5>
@code {
protected override async Task OnInitializedAsync()
{
PriceService.BinancePrice.PropertyChanged += async (sender, e) => { await InvokeAsync(StateHasChanged); };
await base.OnInitializedAsync();
}
async void OnPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
await InvokeAsync(StateHasChanged);
}
public void Dispose()
{
PriceService.BinancePrice.PropertyChanged -= OnPropertyChangedHandler;
}
}
它确实显示了数据,但没有实时显示变化,我需要重新打开选项卡或刷新页面才能看到当前数据。目标是 UI 每次价格变化时都会刷新。如果你能帮我解决这个问题,那就太棒了!:)
我无法真正验证问题的根源,尽管在我看来它与价格 class 和 PropertyChangedEventHandler
的调用有关
但是,下面是应该有效的代码示例:
Price.cs
public class Price : INotifyPropertyChanged
{
private double _askPrice;
private double _bidPrice;
private double _spread;
public Price(double askPrice, double bidPrice)
{
_askPrice = askPrice;
_bidPrice = bidPrice;
}
public double AskPrice
{
get => _askPrice;
set => SetProperty(ref _askPrice, value);
}
public double BidPrice
{
get => _bidPrice;
set => SetProperty(ref _bidPrice, value);
}
public double Spread => _askPrice - _bidPrice;
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string
propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
}
PriceService.cs
public class PriceService
{
public Price BinancePrice { get; set; }
double count;
double BestAskPrice;
double BestBidPrice;
public PriceService()
{
BlazorTimer t = new BlazorTimer();
t.SetTimer(3000, 1, 100);
t.CountCompleted += NotifyCompleted;
BestAskPrice = 102.09;
BestBidPrice = 101.03;
BinancePrice = new Price((double)BestAskPrice, (double)BestBidPrice);
}
private void NotifyCompleted(object sender, TimerEventArgs args)
{
count = (double) args.Count;
BestAskPrice += count;
BestBidPrice += count;
BinancePrice.AskPrice = (double)BestAskPrice;
BinancePrice.BidPrice = (double)BestBidPrice;
}
}
注意:PriceService 是一个服务,应该添加到 DI 容器中:
services.AddSingleton<PriceService>();
另请注意,我避免使用静态内容。
注意:为了验证 UI 是否正在更改,我使用了计时器。真的很简陋,你只需要用它看东西没问题,然后应用你的代码...
BlazorTimer.cs
public class BlazorTimer
{
private Timer _timer;
private int count;
private int end;
internal void SetTimer(double interval, int start, int _end)
{
_timer = new Timer(interval);
_timer.Elapsed += Counter;
_timer.Enabled = true;
count = start;
end = _end;
_timer.Start();
}
private void Counter(object sender, ElapsedEventArgs e)
{
count++;
TimerEventArgs args = new TimerEventArgs { Count = count };
OnCountCompleted(args);
}
protected virtual void OnCountCompleted(TimerEventArgs args)
{
EventHandler<TimerEventArgs> handler = CountCompleted;
if (handler != null)
{
handler(this, args);
}
}
public event EventHandler<TimerEventArgs> CountCompleted;
}
public class TimerEventArgs : EventArgs
{
public int Count { get; set; }
}
用法
@*@implements IDisposable*@
@inject PriceService PriceService
<h5>BID: @($"{PriceService.BinancePrice.BidPrice:F2} EUR")</h5>
<h5>ASK: @($"{PriceService.BinancePrice.AskPrice:F2} EUR")</h5>
<h5>Spread: @($"{PriceService.BinancePrice.Spread:F2} EUR")</h5>
@code {
protected override async Task OnInitializedAsync()
{
PriceService.BinancePrice.PropertyChanged += async (sender, e) => { await InvokeAsync(StateHasChanged); };
await base.OnInitializedAsync();
}
//async void OnPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
//{
// await InvokeAsync(StateHasChanged);
//}
//public void Dispose()
//{
// PriceService.BinancePrice.PropertyChanged -= OnPropertyChangedHandler;
//}
}
我有一个小问题,我尝试在我的 Blazor 服务器项目的页面上显示实时数据。在阅读了几篇文章后,我认为这应该可以通过使用 INotifyPropertyChanged 来实现。不幸的是我对此一窍不通,这是我尝试过的:
我使用 INotifyPropertyChanged 的模型价格(使用 Rider 生成):
public class Price : INotifyPropertyChanged
{
private double _askPrice;
private double _bidPrice;
private double _spread;
public Price(double askPrice, double bidPrice)
{
_askPrice = askPrice;
_bidPrice = bidPrice;
}
public double AskPrice {
get => _askPrice;
set
{
_askPrice = value;
OnPropertyChanged("AskPrice");
OnPropertyChanged("Spread");
}
}
public double BidPrice
{
get => _bidPrice;
set
{
_bidPrice = value;
OnPropertyChanged("BidPrice");
OnPropertyChanged("Spread");
}
}
public double Spread => _askPrice - _bidPrice;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
如何获取实时数据:
public class PriceService
{
public static Price BinancePrice;
public static void StartBinanceStream()
{
var client = new BinanceSocketClient();
// subscribe to updates on the spot API
client.Spot.SubscribeToBookTickerUpdates("BTCEUR", data =>
{
BinancePrice = new Price((double)data.BestAskPrice, (double)data.BestBidPrice);
});
}
}
最后是我的 razorfile 的内容:
<h5>BID: @($"{PriceService.BinancePrice.BidPrice:F2} EUR")</h5>
<h5>ASK: @($"{PriceService.BinancePrice.AskPrice:F2} EUR")</h5>
<h5>Spread: @($"{PriceService.BinancePrice.Spread:F2} EUR")</h5>
@code {
protected override async Task OnInitializedAsync()
{
PriceService.BinancePrice.PropertyChanged += async (sender, e) => { await InvokeAsync(StateHasChanged); };
await base.OnInitializedAsync();
}
async void OnPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
await InvokeAsync(StateHasChanged);
}
public void Dispose()
{
PriceService.BinancePrice.PropertyChanged -= OnPropertyChangedHandler;
}
}
它确实显示了数据,但没有实时显示变化,我需要重新打开选项卡或刷新页面才能看到当前数据。目标是 UI 每次价格变化时都会刷新。如果你能帮我解决这个问题,那就太棒了!:)
我无法真正验证问题的根源,尽管在我看来它与价格 class 和 PropertyChangedEventHandler
的调用有关但是,下面是应该有效的代码示例:
Price.cs
public class Price : INotifyPropertyChanged
{
private double _askPrice;
private double _bidPrice;
private double _spread;
public Price(double askPrice, double bidPrice)
{
_askPrice = askPrice;
_bidPrice = bidPrice;
}
public double AskPrice
{
get => _askPrice;
set => SetProperty(ref _askPrice, value);
}
public double BidPrice
{
get => _bidPrice;
set => SetProperty(ref _bidPrice, value);
}
public double Spread => _askPrice - _bidPrice;
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string
propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
}
PriceService.cs
public class PriceService
{
public Price BinancePrice { get; set; }
double count;
double BestAskPrice;
double BestBidPrice;
public PriceService()
{
BlazorTimer t = new BlazorTimer();
t.SetTimer(3000, 1, 100);
t.CountCompleted += NotifyCompleted;
BestAskPrice = 102.09;
BestBidPrice = 101.03;
BinancePrice = new Price((double)BestAskPrice, (double)BestBidPrice);
}
private void NotifyCompleted(object sender, TimerEventArgs args)
{
count = (double) args.Count;
BestAskPrice += count;
BestBidPrice += count;
BinancePrice.AskPrice = (double)BestAskPrice;
BinancePrice.BidPrice = (double)BestBidPrice;
}
}
注意:PriceService 是一个服务,应该添加到 DI 容器中:
services.AddSingleton<PriceService>();
另请注意,我避免使用静态内容。 注意:为了验证 UI 是否正在更改,我使用了计时器。真的很简陋,你只需要用它看东西没问题,然后应用你的代码...
BlazorTimer.cs
public class BlazorTimer
{
private Timer _timer;
private int count;
private int end;
internal void SetTimer(double interval, int start, int _end)
{
_timer = new Timer(interval);
_timer.Elapsed += Counter;
_timer.Enabled = true;
count = start;
end = _end;
_timer.Start();
}
private void Counter(object sender, ElapsedEventArgs e)
{
count++;
TimerEventArgs args = new TimerEventArgs { Count = count };
OnCountCompleted(args);
}
protected virtual void OnCountCompleted(TimerEventArgs args)
{
EventHandler<TimerEventArgs> handler = CountCompleted;
if (handler != null)
{
handler(this, args);
}
}
public event EventHandler<TimerEventArgs> CountCompleted;
}
public class TimerEventArgs : EventArgs
{
public int Count { get; set; }
}
用法
@*@implements IDisposable*@
@inject PriceService PriceService
<h5>BID: @($"{PriceService.BinancePrice.BidPrice:F2} EUR")</h5>
<h5>ASK: @($"{PriceService.BinancePrice.AskPrice:F2} EUR")</h5>
<h5>Spread: @($"{PriceService.BinancePrice.Spread:F2} EUR")</h5>
@code {
protected override async Task OnInitializedAsync()
{
PriceService.BinancePrice.PropertyChanged += async (sender, e) => { await InvokeAsync(StateHasChanged); };
await base.OnInitializedAsync();
}
//async void OnPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
//{
// await InvokeAsync(StateHasChanged);
//}
//public void Dispose()
//{
// PriceService.BinancePrice.PropertyChanged -= OnPropertyChangedHandler;
//}
}