Search code examples
c#blazorfunc

Blazor Func Property to return calculated value


Expanding on a prior question, I am having difficulty getting it to work.

To start with the part that Does work, I have a property on a class that happens upon click of a button.

public Func<Task> SelectAction { get; set; }

The razor portion looks like the following (this is all in an effort to remove lambdas which are expensive and slow the page down.)

<div class="cv-selectable" @onclick="row.SelectAction">

The SelectAction is setup like the following:

newClaim.SelectAction = () => SwapClaimSelectedState(newClaim);

The SwapClaimSelectedState essentially changes an internal properties value. This works great. Here is the full code (question to follow.)

The razor page:

@foreach (var row in VisibleDestinations)
{
  if (row.RowType == VirtualCopyRowTypes.Claim)
  {
    <div class="cv-row cv-claim">
      <div>
        <button type="button" class="btn btn-link" @onclick="row.ExpandAction">
          <Icon Name="@row.ExpandStateIcon" height="15" />
        </button>
        <div class="cv-selectable" @onclick="row.SelectAction">
          <button type="button" class="btn btn-link">
            <Icon Name="@row.DetermineClaimsIconState" height="15" />
          </button>
          <span>@row.ClaimDisplay</span>
        </div>
      </div>
    </div>
  }
}

The VisibleDestinations "row" properties in question:

[JsonIgnore]
public Func<Task> SelectAction { get; set; }

[JsonIgnore]
public Func<Task> ExpandAction { get; set; }

[JsonIgnore]
public Func<Task> DetermineClaimsIconState { get; set; }

The loop to setup the VisibleDestinations:

foreach (var claim in AllPerformanceClaimsWithVisgrades)
{
  var newClaim = new VirtualCopyRow
  {
    PerformanceClaimId = claim.PerformanceClaimId,
    RowType = VirtualCopyRowTypes.Claim,
    IsVisible = true,
    ClaimDisplay = $"{claim.Issuer} {claim.Name} {claim.Version}",
  };

  newClaim.ExpandAction = () => SwapCollapsedState(newClaim);
  newClaim.SelectAction = () => SwapClaimSelectedState(newClaim);
  newClaim.DetermineClaimsIconState = () => ClaimSelectedStateIcon(newClaim);
  ...
}

The method that I want to call within the razor syntax essentially returns 1 of 4 possible icon states based on child object selection states. Think none-selected, some-selected and all-selected:

public async Task ClaimSelectedStateIcon(VirtualCopyRow row)
{
  var result = IconNames.Blank;
  var totalChildVisgrades = Destinations
    .Count(x =>
      x.PerformanceClaimId == row.PerformanceClaimId &&
      x.RowType == VirtualCopyRowTypes.Visgrade
    );
  var totalSelectedVisgrades = Destinations
    .Count(x =>
      x.PerformanceClaimId == row.PerformanceClaimId &&
      x.RowType == VirtualCopyRowTypes.Visgrade &&
      x.IsSelected == true
    );

  if (totalChildVisgrades == 0)
    result = IconNames.Blank; // There are no Visgrades on this Claim
  else if (totalSelectedVisgrades == 0)
    result = IconNames.UnselectAll; // There is at least one Visgrade on the Claim and None are selected
  else if (totalChildVisgrades == totalSelectedVisgrades)
    result = IconNames.SelectAll; // There is at least one Visgrade on the Claim and they are All selected
  else
    result = IconNames.SomeSelected; // There is at least two Visgrades on the Claim and at least one but not All are selected

  return result;
}

Question

I have tried multiple permutations of how to define the DetermineClaimsIconState property where I have an in and/or TValue of IconNames and there is always some issue either in code or razor.

I do NOT need this to be a Func if some other type will work. The main requirement is that the code-behind needs to be something similar to:

newClaim.DetermineClaimsIconState = () => ClaimSelectedStateIcon(newClaim);

Where I pass the newClaim object to the ClaimSelectiedStateIcon method.

AND that the razor code is NOT a lambda so it should look similar to:

<Icon Name="@row.DetermineClaimsIconState" height="15" />

UPDATE

After attempting to implement @MrC-aka-shaun-curtis updates, the c# is good but the razor gives the following error.

Razor error


Solution

  • Thanks to @mrc-aka-shaun-curtis for assistance. The final product is:

    public Func<VirtualizedRow, IconNames> GetBulkCopyIconState { get; set; }
    public IconNames BulkIconStateForRow
    {
      get
      {
        var result = IconNames.Blank;
    
        if (GetBulkCopyIconState is not null)
          result = GetBulkCopyIconState.Invoke(this);
    
        return result;
      }
    }
    

    When creating differet rows, they all are setup like the following:

    visgradeRow.GetBulkCopyIconState = (e) => DetermineBulkCopyIconState(visgradeRow);
    

    Do the actual calculation for determining which icon to show:

    public IconNames DetermineBulkCopyIconState(VirtualizedRow row)
    {
      ... Magic sauce
    
      return result;
    }
    

    Using it on the razor page/component:

    <button type="button" class="btn btn-sm btn-link p-0 bulk-copy" @onclick="cell.SecondaryAction">
      <Icon Name="@row.BulkIconStateForRow" height="12" class="@row.BulkIconStateForRow" />
    </button>