Please note that this control has been deprecated and replaced with the Grid component, and as such, we recommend migrating to that control. This will not be receiving any new features, bug fixes will be deprioritized. For help or questions on migrating your codebase to the Data Grid, please contact support.
라이브 데이터를 사용한 Blazor 고성능
Ignite UI for Blazor 라이브 데이터 시나리오에서 고성능을 위해 최적화되었습니다. 빠른 로드 시간, 지연 시간 또는 화면 깜박임이 없는 매끄러운 스크롤링으로 그리드의 열과 행을 완벽하게 가상화하여 Blazor 데이터 그리드 애플리케이션에서 무제한의 행과 열을 원활하게 스크롤할 수 있습니다.
Blazor High Performance with Live Data Example
이 샘플은 수천 개의 재무 기록을 Blazor 데이터 그리드에 바인딩하고, 1개의 열(예: Territory)로 그룹화하고, 몇 밀리초마다 여러 열을 라이브 업데이트하여 이러한 성능을 보여줍니다. 다양한 옵션을 실시간으로 변경할 수 있으며, 지연, 화면 깜박임 또는 시각적 지연 없이 데이터 그리드 성능을 변경할 수 있습니다.
using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using IgniteUI.Blazor.Controls; // for registering Ignite UI modules
namespace Infragistics.Samples
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// registering Ignite UI modules
builder.Services.AddIgniteUIBlazor(
typeof(IgbDataGridModule)
);
await builder.Build().RunAsync();
}
}
}
csusing IgniteUI.Blazor.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Infragistics.Samples
{
public class SalesPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Name { get; set; }
public string ImageName { get; set; }
public string Territory { get; set; }
public int Index { get; set; }
public double AvgSale { get; set; }
public double AvgSaleHeat { get; set; }
public double Change { get; set; }
public double PercentChange { get; set; }
public double YearToDateSales { get; set; }
public DateTime DateValue { get; set; }
public double KPI_0 { get; set; }
public double KPI_1 { get; set; }
public double KPI_2 { get; set; }
public double KPI_3 { get; set; }
public double KPI_4 { get; set; }
public double KPI_5 { get; set; }
public double KPI_6 { get; set; }
public double KPI_7 { get; set; }
}
public class SalesPersonData
{
public static List<SalesPerson> GenerateSalesPeople(int number)
{
string[] firstNames = new string[] {
"Kyle",
"Gina",
"Irene",
"Katie",
"Michael",
"Oscar",
"Ralph",
"Torrey",
"William",
"Bill",
"Daniel",
"Frank",
"Brenda",
"Danielle",
"Fiona",
"Howard",
"Jack",
"Larry",
"Holly",
"Jennifer",
"Liz",
"Pete",
"Steve",
"Vince",
"Zeke"
};
string[] lastNames = new string[] {
"Adams",
"Crowley",
"Ellis",
"Gable",
"Irvine",
"Keefe",
"Mendoza",
"Owens",
"Rooney",
"Waddell",
"Thomas",
"Betts",
"Doran",
"Fitzgerald",
"Holmes",
"Jefferson",
"Landry",
"Newberry",
"Perez",
"Spencer",
"Vargas",
"Grimes",
"Edwards",
"Stark",
"Cruise",
"Fitz",
"Chief",
"Blanc",
"Perry",
"Stone",
"Williams",
"Lane",
"Jobs"
};
string[] genders = new string[] {
"GUY",
"GIRL",
"GIRL",
"GIRL",
"GUY",
"GUY",
"GUY",
"GUY",
"GUY",
"GUY",
"GUY",
"GUY",
"GIRL",
"GIRL",
"GIRL",
"GUY",
"GUY",
"GUY",
"GIRL",
"GIRL",
"GIRL",
"GUY",
"GUY",
"GUY",
"GUY"
};
string[] territories = new string[]{
"Australia",
"Canada",
"Egypt",
"Greece",
"Italy",
"Kenya",
"Mexico",
"Oman",
"Qatar",
"Sweden",
"Uruguay",
"Yemen",
"Bulgaria",
"Denmark",
"France",
"Hungary",
"Japan",
"Latvia",
"Netherlands",
"Portugal",
"Russia",
"Turkey",
"Venezuela",
"Zimbabwe"
};
List<SalesPerson> items = new List<SalesPerson>();
Random r = new Random();
for (int i = 0; i < number; i++)
{
SalesPerson item = new SalesPerson();
int firstIndex = (int)Math.Round(r.NextDouble() * (firstNames.Length - 1));
item.Index = i;
item.FirstName = firstNames[firstIndex];
item.LastName = lastNames[(int)Math.Round(r.NextDouble() * (lastNames.Length - 1))];
item.Name = item.FirstName + item.LastName;
int randomIndex = (int)Math.Round(r.NextDouble() * (firstNames.Length - 1));
if (randomIndex == 0)
{
randomIndex = 1;
}
string value = randomIndex.ToString();
if (randomIndex < 10)
{
value = "0" + value;
}
item.ImageName = SalesPersonData.CreateUri(genders[firstIndex] + value + ".png");
item.Territory = territories[(int)Math.Round(r.NextDouble() * (territories.Length - 1))];
item.AvgSale = Math.Round((r.NextDouble() * 800)) + 200.0;
item.Change = (r.NextDouble() * 40.0) - 20.0;
item.PercentChange = 0;
item.YearToDateSales = Math.Round(r.NextDouble() * 50000);
item.DateValue = DateTime.Today.AddDays(number * -1);
for (int j = 0; j < 8; j++)
{
PropertyInfo info = typeof(SalesPerson).GetProperty("KPI_" + j.ToString());
info.SetValue(item, Math.Round(r.NextDouble() * 100));
}
items.Add(item);
}
return items;
}
public static string CreateUri(string value)
{
return "https://static.infragistics.com/xplatform/images/people/" + value;
}
}
}
cs
@using IgniteUI.Blazor.Controls
<div class="container vertical">
<div class="container vertical">
@if (Data != null)
{
<div style="overflow: hidden">
<IgbDataGrid Height="100%" Width="100%"
@ref="DataGridRef"
AutoGenerateColumns="false"
HeaderClickAction="@HeaderClickAction.SortByMultipleColumnsTriState"
RowHeight="40"
SelectionMode="@DataGridSelectionMode.MultipleRow"
DefaultColumnMinWidth="80"
SortDescriptionsChanged="OnSortDescriptionsChanged"
ColumnShowingAnimationMode="@ColumnShowingAnimationMode.Auto"
ColumnHidingAnimationMode="@ColumnHidingAnimationMode.Auto"
DataSource="Data"
IsRowHoverEnabled="false">
<IgbTextColumn Field="FirstName" HeaderText="First Name" Width="@("*>130")" />
<IgbTextColumn Field="LastName" HeaderText="Last Name" Width="@("*>130")" />
<IgbTextColumn Field="Territory" Width="@("*>130")" />
<IgbNumericColumn Field="YearToDateSales" HeaderText="YTD Sales" Width="@("*>130")"
PositivePrefix="$" ShowGroupingSeparator="true" />
<IgbTemplateColumn Field="AvgSale" HeaderText="Avg. Sale" Width="@("*>120")" HorizontalAlignment="@CellContentHorizontalAlignment.Right"
CellUpdatingScript="onAvgSaleCellUpdating" />
<IgbTemplateColumn Field="Change" Width="@("*>120")" HorizontalAlignment="@CellContentHorizontalAlignment.Right"
CellUpdatingScript="onChangeCellUpdating"/>
<IgbTemplateColumn Field="PercentChange" Width="@("*>140")" HorizontalAlignment="@CellContentHorizontalAlignment.Right"
HeaderText="Change (%)" CellUpdatingScript="onPercentChangeCellUpdating"/>
<IgbDateTimeColumn Field="DateValue" HeaderText="Date" Width="@("*>120")" />
@for (int i = 0; i < 8; i++)
{
string str = "KPI_" + i.ToString();
<IgbNumericColumn Width="@("*>150")" Field="@str" DataBoundScript="onKPIColumnDataBound"/>
}
</IgbDataGrid>
</div>
}
</div>
</div>
@code {
private void OnSortDescriptionsChanged(IgbGridSortDescriptionsChangedEventArgs args)
{
}
private List<SalesPerson> Data;
private IgbDataGrid _grid;
private IgbDataGrid DataGridRef
{
get { return _grid; }
set
{
_grid = value;
this.OnDataGridRef();
StateHasChanged();
}
}
private DateTime lastDataUpdate = new DateTime();
private int interval = 1000;
private Random random = new Random();
protected override void OnInitialized()
{
this.Data = SalesPersonData.GenerateSalesPeople(500);
}
private void OnDataGridRef()
{
var columnGroup = new IgbColumnGroupDescription();
columnGroup.Field = "Territory";
this.DataGridRef.GroupDescriptions.Add(columnGroup);
Task.Delay(1000).ContinueWith((t) => OnTimerTick());
}
private void OnTimerTick()
{
bool sortedBySales = false;
int toChange = (int)Math.Round(this.Data.Count / 10.0);
var toChangeIndexes = new List<bool>();
bool stillAnimating = false;
for (int i = 0; i < this.Data.Count; i++)
{
toChangeIndexes.Add(false);
SalesPerson item = this.Data[i];
if (item.AvgSaleHeat != 0)
{
stillAnimating = true;
}
}
var now = DateTime.Now;
bool intervalElapsed = false;
if ((now - lastDataUpdate).TotalMilliseconds > this.interval)
{
intervalElapsed = true;
}
bool useClear = false;
bool sortingByAvgSale = false;
for (int i = 0; i < this.DataGridRef.SortDescriptions.Count; i++)
{
if (this.DataGridRef.SortDescriptions[i].Field == "AvgSale" || this.DataGridRef.SortDescriptions[i].Field.IndexOf("Change") >= 0)
{
sortingByAvgSale = true;
}
}
bool changing = false;
if (intervalElapsed)
{
this.lastDataUpdate = new DateTime();
for (int i = 0; i < toChange; i++)
{
int index = (int)Math.Round(random.NextDouble() * (this.Data.Count - 1));
toChangeIndexes[index] = true;
}
}
for (int i = 0; i < toChangeIndexes.Count; i++)
{
var item = this.Data[i];
if (toChangeIndexes[i] == true)
{
if (sortingByAvgSale && !useClear)
{
this.DataGridRef.NotifyRemoveItem(this.Data, i, item);
this.RandomizeItem(item);
this.DataGridRef.NotifyInsertItem(this.Data, i, item);
}
else
{
this.RandomizeItem(item);
this.DataGridRef.NotifyUpdateItem(this.Data, i, item, true);
}
if (item.Change > 0)
{
item.AvgSaleHeat = 1;
}
else
{
item.AvgSaleHeat = -1;
}
}
else
{
if (item.AvgSaleHeat > 0)
{
item.AvgSaleHeat -= .06;
if (item.AvgSaleHeat < 0)
{
item.AvgSaleHeat = 0;
}
}
if (item.AvgSaleHeat < 0)
{
item.AvgSaleHeat += .06;
if (item.AvgSaleHeat > 0)
{
item.AvgSaleHeat = 0;
}
}
}
}
//if(sortingByAvgSale && useClear)
//{
// this.DataGridRef.ActualDataSource.QueueAutoRefresh();
//}
if (!sortingByAvgSale || !intervalElapsed)
{
this.DataGridRef.InvalidateVisibleRows();
}
Task.Delay(1000).ContinueWith((t) => OnTimerTick());
}
private void RandomizeItem(SalesPerson item)
{
item.Change = (random.NextDouble() * 40.0) - 20.0;
double prevSale = item.AvgSale;
item.AvgSale += item.Change;
item.PercentChange = ((item.AvgSale / prevSale) * 100.00);
}
}
razorfunction onAvgSaleCellUpdating(column, args) {
let row = args.cellInfo.rowItem;
let priceShiftUp = row.Change >= 0;
let templ = args.cellInfo;
let content = args.content;
let sp = null;
let icon = null;
if (content.childElementCount > 0) {
sp = content.children[0];
icon = content.children[1];
} else {
content.style.textAlign = "right";
sp = document.createElement("span");
icon = document.createElement("span");
sp.style.font = "13px Verdana";
sp.style.verticalAlign = "center";
content.appendChild(sp);
content.appendChild(icon);
icon.style.fontFamily = "Material Icons";
icon.style.fontSize = "13px";
icon.style.fontFeatureSettings = "liga";
icon.style.verticalAlign = "center";
}
sp.textContent = "$" + (+templ.value).toFixed(2);
if (priceShiftUp) {
icon.style.color = "#4EB862";
sp.style.color = "#4EB862";
} else {
icon.style.color = "#FF134A";
sp.style.color = "#FF134A";
}
}
function onChangeCellUpdating(column, args) {
let templ = args.cellInfo;
let priceShiftUp = templ.value >= 0;
let content = args.content;
let sp = null;
if (content.childElementCount > 0) {
sp = content.children[0];
} else {
content.style.textAlign = "right";
sp = document.createElement("span");
sp.style.font = "13px Verdana";
sp.style.verticalAlign = "center";
content.appendChild(sp);
}
sp.textContent = (+templ.value).toFixed(2);
if (priceShiftUp) {
sp.style.paddingRight = "5px";
sp.style.borderRight = "4px solid #4EB862";
} else {
sp.style.paddingRight = "5px";
sp.style.borderRight = "4px solid #FF134A";
}
}
function onPercentChangeCellUpdating(column, args) {
let templ = args.cellInfo;
let priceShiftUp = templ.value >= 0;
let content = args.content;
let sp = null;
if (content.childElementCount > 0) {
sp = content.children[0];
} else {
content.style.textAlign = "right";
sp = document.createElement("span");
sp.style.font = "13px Verdana";
sp.style.verticalAlign = "center";
content.appendChild(sp);
}
sp.textContent = (+templ.value).toFixed(2) + "%";
if (priceShiftUp) {
sp.style.paddingRight = "5px";
sp.style.borderRight = "4px solid #4EB862";
} else {
sp.style.paddingRight = "5px";
sp.style.borderRight = "4px solid #FF134A";
}
}
function onKPIColumnDataBound(column, args) {
let value = args.resolvedValue;
if (value < 20.0) {
if (args.cellInfo.background !== "red") {
args.cellInfo.background = "#FF134A";
}
}
if (value > 80.0) {
if (args.cellInfo.background !== "green") {
args.cellInfo.background = "#4EB862";
}
}
}
igRegisterScript("onAvgSaleCellUpdating", onAvgSaleCellUpdating, false);
igRegisterScript("onChangeCellUpdating", onChangeCellUpdating, false);
igRegisterScript("onPercentChangeCellUpdating", onPercentChangeCellUpdating, false);
igRegisterScript("onKPIColumnDataBound", onKPIColumnDataBound, false);
js/*
CSS styles are loaded from the shared CSS file located at:
https://static.infragistics.com/xplatform/css/samples/
*/
css
Like this sample? Get access to our complete Ignite UI for Blazor toolkit and start building your own apps in minutes. Download it for free.