英文:
Blazor Func Property to return calculated value
问题
在之前的问题的基础上,我在尝试让它工作时遇到了困难。
首先来看确实工作的部分,我在一个类上有一个属性,它会在按钮点击时发生。
public Func<Task> SelectAction { get; set; }
Razor 部分如下(这一切都是为了消除昂贵且减慢页面速度的 lambda 表达式)。
<div class="cv-selectable" @onclick="row.SelectAction">
SelectAction 设置如下:
newClaim.SelectAction = () => SwapClaimSelectedState(newClaim);
SwapClaimSelectedState 实际上会更改内部属性的值。这很有效。以下是完整的代码(问题随后提出)。
Razor 页面:
@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>
  }
}
VisibleDestinations 中的 "row" 属性:
[JsonIgnore]
public Func<Task> SelectAction { get; set; }
[JsonIgnore]
public Func<Task> ExpandAction { get; set; }
[JsonIgnore]
public Func<Task> DetermineClaimsIconState { get; set; }
设置 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);
  // ...
}
我想在 Razor 语法中调用的方法基本上会根据子对象的选择状态返回4种可能的图标状态之一。思考未选择、部分选择和全部选择:
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; // 此索赔上没有 Visgrades
  else if (totalSelectedVisgrades == 0)
    result = IconNames.UnselectAll; // 此索赔上至少有一个 Visgrade,但没有选中任何一个
  else if (totalChildVisgrades == totalSelectedVisgrades)
    result = IconNames.SelectAll; // 此索赔上至少有一个 Visgrade,且全部都选中了
  else
    result = IconNames.SomeSelected; // 此索赔上至少有两个 Visgrade,至少一个被选中但不是全部都选中了
  return result;
}
问题
我尝试了多种方式来定义 DetermineClaimsIconState 属性,其中有一个 in 和/或 TValue 的 IconNames,但无论是在代码还是 Razor 中都会出现问题。
如果其他类型可以工作,我不需要这是一个 Func。主要要求是代码后台需要类似于以下内容:
newClaim.DetermineClaimsIconState = () => ClaimSelectedStateIcon(newClaim);
在 Razor 代码中不是 Lambda,所以它应该类似于:
<Icon Name="@row.DetermineClaimsIconState" height="15" />
更新
在尝试实现 @MrC-aka-shaun-curtis 的更新后,C# 部分是正确的,但 Razor 部分出现了以下错误。
英文:
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.
答案1
得分: 1
看着你的方法 ClaimSelectedStateIcon:
- 返回类型是 
Task,但你尝试返回一个IconValues对象 [我假设是一个枚举?]。 - 我没有看到任何异步方法调用,所以我假设你正在收到关于这方面的警告。
 
它应该像这样:
public Task<IconNames> ClaimSelectedStateIcon(VirtualCopyRow row)
{
  var result = IconNames.Blank;
    //....
  return Task.FromResult(result);
}
而你的委托声明:
public Func<Task<IconNames>> DetermineClaimsIconState { get; set; }
英文:
Looking at your method ClaimSelectedStateIcon:
- The return type is 
Task, but you try to return anIconValuesobject [I assume an enum?]. - I see no async methods called so I assume you're getting warnings about that.
 
It should look like:
public  Task<IconNames> ClaimSelectedStateIcon(VirtualCopyRow row)
{
  var result = IconNames.Blank;
    //....
  return Task.FromResult(result);
}
And your delegate declared:
public Func<Task<IconNames>> DetermineClaimsIconState { get; set; }
答案2
得分: 0
感谢 @mrc-aka-shaun-curtis 的协助。最终产品是:
    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;
      }
    }
当创建不同行时,它们都设置如下:
    visgradeRow.GetBulkCopyIconState = (e) => DetermineBulkCopyIconState(visgradeRow);
进行实际计算以确定显示哪个图标:
    public IconNames DetermineBulkCopyIconState(VirtualizedRow row)
    {
      ... 魔法酱
      return result;
    }
在 Razor 页面/组件上使用:
    <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>
英文:
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论