使用Blazor構建投資回報計算器

本文由葡萄城技術團隊原創並首發。轉載請註明出處:葡萄城官網,葡萄城爲開發者提供專業的開發工具、解決方案和服務,賦能開發者。

前言

本博客中創建的投資計算器根據存入金額和回報率計算每個投資週期的特定回報。作爲累積衡量標準,它計算指定時間內賺取的總利息以及當前投資的未來價值。以下是我們將在接下來的部分中學習設計的計算器的快速視圖:

以下步驟將幫助進一步演示我們如何使用 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,展示了正在運行的投資計算器:


葡萄城好課推薦:
Redis從入門到實踐

一節課帶你搞懂數據庫事務!

Chrome開發者工具使用教程

擴展鏈接:

從表單驅動到模型驅動,解讀低代碼開發平臺的發展趨勢

低代碼開發平臺是什麼?

基於分支的版本管理,幫助低代碼從項目交付走向定製化產品開發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章