本文由葡萄城技术团队原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

前言

本博客中创建的投资计算器根据存入金额和回报率计算每个投资周期的特定回报。作为累积衡量标准,它计算指定时间内赚取的总利息以及当前投资的未来价值。以下是我们将在接下来的部分中学习设计的计算器的快速视图:

以下步骤将帮助进一步演示我们如何使用 Blazor 创建此投资计算器。

使用 FlexGrid 设置 Blazor 应用程序

我们首先使用 Blazor 服务器应用程序模板创建 Blazor 应用程序:

创建应用程序后,我们需要使用 Nuget Package Manager 安装C1.Blazor.FlexGrid包,并添加所需的客户端引用以开始使用 FlexGrid 控件。FlexGrid快速入门可以为您提供有关如何将 FlexGrid 控件添加到 Blazor 应用程序的详细步骤。

FlexGrid 在绑定和非绑定模式下都能很好地工作。对于此应用程序,我们将使用 FlexGrid 的非绑定模式,因为我们需要输入一些值,根据这些值执行计算以填充 FlexGrid 中的其他单元格。请参阅描述 FlexGrid 的非绑定模式的演示和文档。

下面的代码假设项目已根据 FlexGrid 快速入门进行配置,并且 Razor 组件已添加到项目中。现在,将以下代码添加到 razor 页面,通过显式添加所需的行数和列数来添加和配置 FlexGrid 控件以实现非绑定模式:

@page "/"
@using C1.Blazor.Core
@using C1.Blazor.Grid <FlexGrid @ref="grid"
CellFactory="@cellFactory"
MergeManager="@custommergemanager"
HeadersVisibility="GridHeadersVisibility.None"
SelectionMode="GridSelectionMode.Cell"
GridLinesVisibility="GridLinesVisibility.None"
CellEditEnded="OnCellEditEnded" BeginningEdit="OnBeginningEdit" SelectionChanging="OnSelectionChanging"
Style="@("max-height:100vh; max-width:97vh;position: absolute; top: 10%; left: 25%; ")">
<FlexGridColumns>
<GridColumn Width="14" IsReadOnly="true" />
<GridColumn Width="67" IsReadOnly="true" />
<GridColumn Width="147" Format="c2" IsReadOnly="true" />
<GridColumn Width="147" Format="c2" IsReadOnly="true" />
<GridColumn Width="147" Format="c2" IsReadOnly="true" />
<GridColumn Width="164" Format="c2" />
<GridColumn Width="14" IsReadOnly="true" />
</FlexGridColumns>
<FlexGridRows>
@for (int i = 0; i < 378; i++)
{
if (i == 0)
{
<GridRow Height="50" />
}
else
{
<GridRow Height="25" />
}
}
</FlexGridRows>
</FlexGrid> @code
{
FlexGrid grid;
GridCellFactory cellFactory = new CustomCellFactory();
CustomMergeManager custommergemanager = new CustomMergeManager();
}

如何设计 Blazor 计算器布局

现在,让我们开始自定义 FlexGrid 外观,使其类似于投资计算器。我们可以通过调整列宽、行高、合并单元格、格式化单元格以及将计算器字段标签填充到 FlexGrid 中适当的单元格来实现相同的目的。以下部分将为您提供有关应用所有所需自定义的详细信息。

合并单元格

FlexGrid 提供对跨行或列合并单元格的内置支持,前提是相邻单元格具有相同的内容。我们可以通过继承GridMergeManager类来自定义FlexGrid的默认合并行为,定义跨行和列合并单元格的自定义逻辑。

对于此实现,我们需要定义一个自定义 MergeManager,它将合并 FlexGrid 中预定义的单元格列表,以便为投资计算器呈现适当的单元格表示形式。下面的代码合并 FlexGrid 中所需的单元格:

//Define custom MergeManager class to merge cell ranges based on custom logic
public class CustomMergeManager : GridMergeManager
{
public override GridCellRange GetMergedRange(GridCellType cellType, GridCellRange range)
{
//Merge cells containing Calculator title
if (cellType == GridCellType.Cell && (range.Row == 0 && range.Column >= 0 && range.Column <= 5))
{
GridCellRange range1 = new GridCellRange(0, 0, 0, 5);
return range1;
} //Merge cells containing calculator description
if (cellType == GridCellType.Cell && range.Column >= 1 && range.Column <= 2)
{
if (range.Row == 2 || range.Row == 3 || range.Row == 5 || range.Row == 6 || range.Row == 8 || range.Row == 9)
{
GridCellRange range2 = new GridCellRange(range.Row, 1, range.Row, 2);
return range2;
}
} //Merge cells containing calculator field labels
if (cellType == GridCellType.Cell && range.Column >= 3 && range.Column <= 4)
{
if (range.Row == 2 || range.Row == 3 || range.Row == 4 || range.Row == 6 || range.Row == 7 || range.Row == 8 || range.Row == 10 || range.Row == 11)
{
GridCellRange range3 = new GridCellRange(range.Row, 3, range.Row, 4);
return range3;
}
} return base.GetMergedRange(cellType, range); }
}
}

添加字段标签

在下面的代码中,我们将投资计算器字段标签填充到未绑定 FlexGrid 的相应单元格中:

//Override AfterRender method to populate grid for Calculator fields
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
GenerateCalculator();
} // Fill unbound grid to showcase calculator fields and results
private void GenerateCalculator()
{
//Populate calculator field labels
grid[0, 0] = "Investment Calculator"; grid[2, 1] = "Calculate your investment ";
grid[3, 1] = "returns.";
grid[5, 1] = "Enter values into the yellow";
grid[6, 1] = " boxes.";
grid[8, 1] = "Results will be shown in the ";
grid[9, 1] = "green boxes."; grid[2, 3] = "Initial Investment Amount:";
grid[3, 3] = "Annual Rate of Return:";
grid[4, 3] = "Deposit Amount per Period:"; grid[6, 3] = "Duration of Investment (In Years):";
grid[7, 3] = "Number of Deposits Per Year:";
grid[8, 3] = "Total Number of Periods (Upto 360):"; grid[10, 3] = "Total Interest Income:";
grid[11, 3] = "Ending Balance(FV):"; grid[15, 1] = "Period";
grid[15, 2] = "Initial Balance";
grid[15, 3] = "Interest Earned";
grid[15, 4] = "New Deposit";
grid[15, 5] = "New Balance"; //Populate initial values for initial investment Amount, Return rate and deposit amount per period
grid[2, 5] = 5000;
grid[3, 5] = Convert.ToString(10) + "%";
grid[4, 5] = 100; //Populate initial values for Investment duration(in years), number of deposits per year
grid[6, 5] = Convert.ToString(30);
grid[7, 5] = Convert.ToString(12); //Invoke method to calculate investment return
CalculateReturn();
}

应用单元格样式

我们已在适当的合并单元格中添加了所有必需的标签。现在,让我们对单元格应用样式,以增强投资计算器的外观和感觉,并使其看起来更加真实。要将样式应用于 FlexGrid 中的单元格,请继承GridCellFactory类以创建自定义 CellFactory 类,该类可让您单独设置每个单元格的样式。您可以通过应用背景颜色、前景色、边框、字体等来设置单元格的样式。

下面的代码定义了一个自定义 CellFactory 并设置 FlexGrid 中所有单元格的样式:

public override void PrepareCellStyle(GridCellType cellType, GridCellRange range, C1Style style, C1Thickness internalBorders)
{
base.PrepareCellStyle(cellType, range, style, internalBorders); //Style Calculator border
if (cellType == GridCellType.Cell)
{
if (range.Column == 0 && range.Row >= 1 && range.Row <= 376)
{
style.BorderColor = C1Color.Black;
style.BorderLeftWidth = new C1Thickness(2);
} if (range.Column == 6 && range.Row >= 1 && range.Row <= 376)
{
style.BorderColor = C1Color.Black;
style.BorderRightWidth = new C1Thickness(2);
} if (range.Row == 0)
{
style.BorderColor = C1Color.Black;
style.BorderBottomWidth = new C1Thickness(2);
} if (range.Row == 376)
{
style.BorderColor = C1Color.Black;
style.BorderBottomWidth = new C1Thickness(2);
}
} //Style calculator title
if (cellType == GridCellType.Cell && range.Column >= 0 && range.Column <= 6 && range.Row == 0)
{
style.BackgroundColor = C1Color.FromARGB(255, 112, 173, 70); ;
style.FontSize = 32;
style.FontWeight = "Arial";
style.Color = C1Color.White;
} //Style calculator description
if (cellType == GridCellType.Cell && range.Column == 0 && range.Row == 3)
{
style.FontSize = 10;
style.FontWeight = "Arial";
} //Style Calculator fields labels and inputs
if (cellType == GridCellType.Cell && range.Column >= 3 && range.Column <= 4)
{
if (range.Row >= 2 && range.Row <= 11)
{
if (range.Row != 5 && range.Row != 9)
{
style.BorderColor = C1Color.Black;
style.BorderWidth = new C1Thickness(1);
style.BackgroundColor = C1Color.FromARGB(255, 112, 173, 70);
style.Color = C1Color.White;
style.JustifyContent = C1StyleJustifyContent.FlexEnd;
}
}
if (range.Row == 12 && range.Column >= 3 && range.Column <= 4)
{
style.BorderColor = C1Color.Black;
style.BorderTopWidth = new C1Thickness(1);
}
} if (cellType == GridCellType.Cell && range.Column == 5)
{
if (range.Row >= 2 && range.Row <= 7)
{
if (range.Row != 5)
{
style.BorderColor = C1Color.Black;
style.BorderWidth = new C1Thickness(1);
style.BackgroundColor = C1Color.White;
style.JustifyContent = C1StyleJustifyContent.FlexEnd;
}
} if (range.Row >= 8 && range.Row <= 11)
{
if (range.Row != 9)
{
style.BorderColor = C1Color.Black;
style.BorderWidth = new C1Thickness(1);
style.BackgroundColor = C1Color.FromARGB(255, 226, 239, 219);
style.JustifyContent = C1StyleJustifyContent.FlexEnd;
}
} if (range.Row == 12)
{
style.BorderColor = C1Color.Black;
style.BorderTopWidth = new C1Thickness(1);
}
} //Style investment return table
if (cellType == GridCellType.Cell && range.Column >= 1 && range.Column <= 5)
{
if (range.Row >= 15 && range.Row <= 375)
{
if (range.Row == 15)
{
style.BackgroundColor = C1Color.FromARGB(255, 112, 173, 70);
style.Color = C1Color.White;
style.JustifyContent = C1StyleJustifyContent.Center;
}
else
{
if (range.Row % 2 == 0)
style.BackgroundColor = C1Color.FromARGB(255, 226, 239, 219);
else
style.BackgroundColor = C1Color.FromARGB(255, 255, 255, 255);
style.JustifyContent = C1StyleJustifyContent.FlexEnd;
} if (range.Column == 1)
{
style.JustifyContent = C1StyleJustifyContent.Center;
}
} if (range.Row == 376)
{
style.BorderColor = C1Color.Black;
style.BorderTopWidth = new C1Thickness(1);
}
}
}
}

以下是 FlexGrid 控件的快速浏览,在执行上述所有步骤后,该控件被设计为投资计算器:

实施投资计算器计算

上面设计的投资计算器具有三种色调。深绿色用于指定包含字段标签的单元格,这些标签是静态值。白色单元格是输入单元格,用户在其中输入所需的值来执行计算,浅绿色用于表示显示计算值的单元格,这些值是在此计算器中执行的所有计算的结果,因此投资回报。在所有这些单元格中,只有白色单元格是可编辑的,因为它们需要用户输入。

在本节中,我们将定义一个方法来执行所有计算以计算投资回报。以下方法计算每个投资期的投资回报、赚取的总利息以及投资的未来价值。使用基本运算符加、减、乘、除进行的计算很少。为了计算投资的未来价值,我们需要使用财务函数FV。

必须安装Microsoft.VisualBasic包才能调用 C#.Net 中财务函数。Microsoft.VisualBasic 命名空间的 Financial 类中提供了不同的财务函数。在下面的代码中,我们使用了Financial 类中的FV财务函数。

请参阅下面的代码,了解如何在 C# 中实现各种计算,以使计算器正常工作并使用适当的投资回报值填充单元格。

//Method to calculate investment return
public async Task<bool> CalculateReturn()
{
//Fetch initial investment amount
int initialAmt = Convert.ToInt32(grid[2, 5]); //Fetch Rate of return by removing percentage sign
string rate = (string)grid[3, 5];
int ror = Convert.ToInt32(rate.Replace("%", " ")); //Fetch deposit amount
int depositAmt = Convert.ToInt32(grid[4, 5]); //Fetch total duration of investment(in years)
int investmentYears = Convert.ToInt32(grid[6, 5]); //Fetch number of deposits in an year
int numDeposits = Convert.ToInt32(grid[7, 5]); //Calculate total number of periods and assign to respective grid cell
int totalPeriods = investmentYears * numDeposits; //Make sure total number of periods is not more than 360
if (totalPeriods <= 360)
{
grid[8, 5] = Convert.ToString(totalPeriods);
}
else
{
grid[8, 5] = null;
await JsRuntime.InvokeVoidAsync("alert", "Please make sure total number of periods is upto 360 !!");
return false;
} //Calculate investment return for each period in investment duration
for (int period = 1, row = 16; row <= 375; row++, period++)
{
if (period <= totalPeriods)
{
grid[row, 1] = period;
if (row == 16)
{
grid[row, 2] = initialAmt;
}
else
{
grid[row, 2] = grid[row - 1, 5];
}
grid[row, 3] = (((Convert.ToDouble(ror) / Convert.ToDouble(numDeposits)) * Convert.ToInt32(grid[row, 2])) / 100);
grid[row, 4] = depositAmt;
grid[row, 5] = Convert.ToInt32(grid[row, 2]) + Convert.ToDouble(grid[row, 3]) + Convert.ToInt32(grid[row, 4]);
}
else
{
grid[row, 1] = grid[row, 2] = grid[row, 3] = grid[row, 4] = grid[row, 5] = null;
}
} //Calculate Future Value of investment/Ending Balance
double Rate = Convert.ToDouble(ror) / (Convert.ToDouble(numDeposits) * 100);
double NPer = Convert.ToDouble(totalPeriods);
double Pmt = Convert.ToInt32(depositAmt);
double PV = Convert.ToInt32(initialAmt);
double fv = -(Financial.FV(Rate, NPer, Pmt, PV));
grid[11, 5] = fv; //Calculate total interest income
double endingBal = fv - initialAmt - (depositAmt * totalPeriods);
grid[10, 5] = endingBal; return true;
}

自定义UI交互

由于投资计算器是使用 FlexGrid 创建的,因此必须处理与编辑和选择相关的 FlexGrid 的默认行为以满足计算器的行为。本节描述了更改计算器的用户交互行为必须处理的所有 FlexGrid 事件。

首先,我们需要处理FlexGrid 的CellEditEnded事件,以确保每当用户更改计算器中的任何输入值(即回报率、初始投资金额、存款金额或投资期限)时,计算器必须重新计算所有投资回报值。

下面的代码实现了上述行为:

//Handle Flexgrid's CellEditEdited event to recalcuate investment return
//when either of the values Rate of Return, Deposit Amount etc. are changed
public async void OnCellEditEnded(object sender, GridCellRangeEventArgs e)
{
//Parse string input value to int and assign to cell
if (e.CellRange.Row == 2 || e.CellRange.Row == 4)
{
grid[e.CellRange.Row, e.CellRange.Column] = Convert.ToInt32((string)grid[e.CellRange.Row, e.CellRange.Column]);
} //Add percentage sign to Rate of Return
if (e.CellRange.Row == 3)
{
grid[e.CellRange.Row, e.CellRange.Column] = (string)grid[e.CellRange.Row, e.CellRange.Column] + "%";
} //Invoke method to reclaculate investment return based on new values.
await CalculateReturn();
}

接下来,我们处理FlexGrid的BeginningEdit事件来限制FlexGrid中的编辑。如上所述,FlexGrid 中的所有单元格都不应该是可编辑的。用户应该能够仅编辑那些需要用户输入值的单元格。

因此,下面的代码处理 BeginningEdit 事件以实现上述行为:

//Handle Flexgrid's BeginningEdit event to cancel editing for cells.
public void OnBeginningEdit(object sender, GridCellRangeEventArgs e)
{
if (e.CellRange.Row >= 8 && e.CellRange.Row <= 375)
e.Cancel = true;
}

最后,我们处理FlexGrid 的SelectionChanging事件,以确保用户只能选择 FlexGrid 中的可编辑单元格:

//Handle Flexgrid's SelectionChanging event to disable selection of non editable cells.
public void OnSelectionChanging(object sender, GridCellRangeEventArgs e)
{
if (!(e.CellRange.Row >= 2 && e.CellRange.Row <= 7))
{
if (e.CellRange.Row != 5)
e.Cancel = true;
}
else if (e.CellRange.Column >= 1 && e.CellRange.Column <= 4)
{
e.Cancel = true;
}
}

下面是一个 GIF,展示了正在运行的投资计算器:

扩展链接:

从表单驱动到模型驱动,解读低代码开发平台的发展趋势

低代码开发平台是什么?

基于分支的版本管理,帮助低代码从项目交付走向定制化产品开发

使用Blazor构建投资回报计算器的更多相关文章

  1. python 利用正则构建一个计算器

    该计算器主要分为四个模块: weclome_func函数用来进入界面获取表达式,并判断表达式是否正确,然后返回表达式: add_sub函数用来进行加减运算,如果有多个加减运算,会递归,最后返回对应的值 ...

  2. 《进击吧!Blazor!》第一章 4.数据交互

    <进击吧!Blazor!>是本人与张善友老师合作的Blazor零基础入门系列视频,此系列能让一个从未接触过Blazor的程序员掌握开发Blazor应用的能力. 视频地址:https://s ...

  3. Ant Design Blazor 组件库的路由复用多标签页介绍

    最近,在 Ant Design Blazor 组件库中实现多标签页组件的呼声日益高涨.于是,我利用周末时间,结合 Blazor 内置路由组件实现了基于 Tabs 组件的 ReuseTabs 组件. 前 ...

  4. 浅谈Blazor开发的那些事

    在这篇文章中,我们将解决一些常见的Blazor问题.具体来说就是"什么是Blazor",但更重要的是"为什么要用Blazor".既然我们已经有了Angular. ...

  5. 用python做个计算器不是轻轻松松吗~

    计算器 Kivy是一个免费的开源Python库,可以快速轻松地开发高度交互的跨平台应用程序. 这里我将使用Python中的Kivy包来构建一个计算器GUI.(https://jq.qq.com/?_w ...

  6. Blazor VS Vue

    Vue--​​两分钟概述 Vue 是一个JavaScript 框架. 在其最简单的模式中,您可以简单地将核心 Vue 脚本包含在您的应用程序中,然后开始构建您的组件. 除此之外,对于更复杂的应用程序, ...

  7. 第8章 使用标记帮助工具构建表单(ASP.NET Core in Action, 2nd Edition)

    本章包括 使用Tag Helpers轻松构建表单 使用锚标记帮助程序生成URL 使用Tag Helpers为Razor添加功能 在第7章中,您了解了Razor模板以及如何使用它们为应用程序生成视图.通 ...

  8. ApacheCN C# 译文集 20211124 更新

    C# 代码整洁指南 零.前言 一.C# 代码标准和原则 二.代码审查--过程和重要性 三.类.对象和数据结构 四.编写整洁的函数 五.异常处理 六.单元测试 七.端到端系统测试 八.线程和并发 九.设 ...

  9. 通过 LPeg 介绍解析表达式语法(Parsing Expression Grammars)

    通过 LPeg 介绍解析表达式语法(Parsing Expression Grammars) 译者: FreeBlues 修订版本: 1.00 最新链接: http://www.cnblogs.com ...

  10. 0512 SCRUM团队项目3.0

    题目 SCRUM 流程的步骤2: Spring 计划 1. 确保product backlog井然有序.(参考示例图1) 2. Sprint周期,一个冲刺周期,长度定为两周,本学期还有三个冲刺周期. ...

随机推荐

  1. Djiango 创建迁移项报错query = query.decode(errors='replace') AttributeError: 'str' object has no attribute 'decode'

    在终端命令行创建迁移项 输入(python manage.py makemigrations) 或(python manage.py migrate)时出现报错信息:Traceback (most r ...

  2. 安装Hadoop单节点伪分布式集群

    目录 安装Hadoop单节点伪分布式集群 系统准备 开启SSH 安装JDK 安装Hadoop 下载 准备启动 伪分布式模式安装 配置 配饰SSH免密登录本机 测试启动 单节点安装YARN 伪分布式集群 ...

  3. P5752 [NOI1999] 棋盘分割题解

    本文来自我的洛谷博客. 这个题解思路虽然与其他人的思路相同, 但力求使用清晰易懂的图片和文字,讲解最简洁的道理. 请大家耐心地看完,注意要结合图片一起哦~~ 2022-8-24 更改了格式与错别字. ...

  4. 一文帮你搞定H5、小程序、Taro长列表曝光埋点

    对于很多前端同学来说,"埋点"常常是一个不愿面对却又无法逃避的话题.为什么这么说呢,相信很多前端同学都深有体会:首先埋点这个事基本是前端"独享"的,服务端基本不 ...

  5. 并发编程-FutureTask解析

    1.FutureTask对象介绍 Future对象大家都不陌生,是JDK1.5提供的接口,是用来以阻塞的方式获取线程异步执行完的结果. 在Java中想要通过线程执行一个任务,离不开Runnable与C ...

  6. 趣图|代码重构前vs重构后

    前言 很多程序员对自己写的代码平时很随心所欲,但当有一天让他维护他人的代码,他就会抓狂,很容易激发他体内重构的瘾.(大多数程序员审阅完别人代码后,先会忍不住吐槽一番,然后会忍不住想重构一把,) 在我看 ...

  7. html中的一些常用标签与标签属性

    label for属性 定义和用法 for 属性规定 label 与哪个表单元素绑定. <span> <label for="username">用户账号& ...

  8. ubuntu 安装sublime

    Install the GPG key: wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key ad ...

  9. C# 多线程访问之 SemaphoreSlim(信号量)【进阶篇】

    SemaphoreSlim 是对可同时访问某一共享资源或资源池的线程数加以限制的 Semaphore 的轻量替代,也可在等待时间预计很短的情况下用于在单个进程内等待. 由于 SemaphoreSlim ...

  10. FreeRTOS 基于 ARMv8-M 对 MPU 的应用

    一.前言 ARMv8-M 支持 MPU,FreeRTOS 也添加了对这些 MPU 的应用代码.这里用来记录 FreeRTOS 对 MPU 应用方式的探究结果. 二.ArmV8-M MPU 介绍 ARM ...