簡體   English   中英

如何實現通用視圖 Model 在視圖組件中顯示動態表

[英]How to implement a Generic View Model To Display dynamic table in view component

我正在嘗試定義 Columns 對象的列表,這些對象也知道從該行中的 object 獲取什么屬性。

public class Column<T> 
{
   //Column Heading
   public string Name { get; set; }
   //Mapping Expression
   public Expression<Func<T, string>> ValueMapper { get; set; }
}

public class Row<T>
{
   T Data { get; set; }
}

public class Table<T>
{
   IEnumerable<Row<T>> Rows { get; set; }
   IEnumerable<Column<T>> Columns { get; set; }
}

然后我計划有一個視圖,我可以將Table<T>作為視圖作為視圖組件傳遞給視圖組件,該視圖組件可以以動態方式顯示任何類型列表的表......而不是單獨定義所有表.

我的問題是我無法指定通用視圖 model 並且類型約束似乎不起作用..並且表達式不允許協方差。

這可能嗎? 任何幫助,將不勝感激。

編輯:

最后,我想在 razor 視圖中實現類似的效果。

(在上面將 T 的類型約束設置為where T: IData

@model Table<IData>

<table>
    <thead>
        <tr>
        @foreach(var col in Model.Columns) 
        {
            <td>@col.Name</td>
        }
        </tr>
    </thead>
    <tbody>
    @foreach(var row in Model.Rows)
    {
       <tr>
           @foreach(var col in Model.Columns)
           {
                <td>@col.ValueMapper.Compile().Invoke(row.Data)</td>
           }
       </tr>
    }
    </tbody>
</table>

我的問題似乎是我不能將一些具體的Table<T>實現隱式轉換/傳遞給視圖 model。 我認為 Variance 是答案,但我無法讓它工作,因為 1) Row<T>上的 Data 屬性具有 getter 和 setter 意味着它是不變的,對嗎? 和 2) Expression<Func<T, string>>屬性也有 getter 和 setter,並且還接受 T 作為 Func<in T1, out T2> 中的類型參數。所以我認為有一種方法可以實現這一點。我只是跌跌撞撞。

編輯2:

我能夠實現我想要的,但不得不放棄 lamda 表達式。我真的很想使用它,但無法讓它工作。我還刪除了所有 generics。 而不是具有“T”的屬性(T Data { get; set; }),而是將其鍵入object .. 而不是在列 class 上存儲表達式,而是存儲字符串屬性名稱。 行 class 使用屬性名稱來使用反射獲取屬性值。 很遺憾我不得不使用反射,但它正在工作..我仍在尋找更好的方法。

public class Table
{
    public IEnumerable<Column> Columns {get; set;}
    public IEnumerable<Row> Rows {get; set;}
}  

public class Row
{
  public object Data {get; set;}
  public string GetValue(string propertyName) 
  {
    var toReturn = "";
    var pi = Data.GetType().GetProperty(propertyName);
    var value = pi.GetValue(Data);
    if(value == null) 
        return toReturn;

    if(value is DateTime dt)
        toReturn = dt.ToShortDateString();
    else
        toReturn = value.ToString();

     return toReturn;
  }
}

public class Column
{
   public string Name {get; set;}
   public string PropertyName {get; set;}
}

在視圖中


@foreach(var row in Model.Rows)
    {
       <tr>
           @foreach(var col in Model.Columns)
           {
                <td>@row.GetValue(col.PropertyName)</td>
           }
       </tr>
    }

您可以創建一個接受通用表並將列名和值公開為簡單字符串的包裝器:

class ViewModel
{
    public IReadOnlyCollection<string> Columns { get; init; }
    public IReadOnlyCollection<IReadOnlyCollection<string>> Rows { get; init; }

    public static ViewModel ForTable<T>(Table<T> table)
    {
        var columns = table.Columns.Select(column => column.Name).ToArray();
        var rows = table.Rows
            .Select(row => table.Columns
                .Select(column => column.ValueMapper(row.Data).ToArray())
            .ToArray();

        return new ViewModel
        {
            Columns = columns,
            Rows = rows
        };
    }
}

您不需要通過這種方法使用Expression

public class Column<T> 
{
   //Column Heading
   public string Name { get; set; }
   //Mapping Expression
   public Func<T, string> ValueMapper { get; set; }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM