asp.Net GridViewはカスタムオブジェクトをネストされたリストにバインドします
-
08-07-2019 - |
質問
カスタムリストで構成されているカスタムオブジェクトのリストがあります。
class person{
string name;
int age;
List<friend> allMyFriends;
}
class friend{
string name;
string address;
}
これらのオブジェクトのリストをGridViewにバインドしようとしていますが、Gridは友人ごとに列を作成し、名前を書き込む必要があります。同じフリンジを持っている人がいる場合、グリッドは別の列を作成するのではなく、既存の列を使用します。私の言っていることが分かるよね。 (クラスは、私のケースを簡素化するための単なるサンプルクラスです)
バインディングを動的にカスタマイズする方法はありますか
一部のインターフェースなどから継承する必要がある場合、クラス定義などを変更できます。
よくGoogleで検索しましたが、この事例をカバーする例は実際にはありませんでした。
objectSourceControlを使用すると、何らかの方法で問題を解決できますか?
更新:
さらに情報を提供するには: 最後に、個人のリストがありますが、リスト内の各個人には友人のリストがあります。
List<person> allPerson = new List<person>();
// fill the list
Grid.DataSource = allPerson;
Grid.DataBind()
テーブルには各友人の列があり、行は人です。人に友人がいる場合、グリッドにクロス(または何でも)を配置する必要があります。
friend1 friend2
x peter
x x adam
現時点では、RowDataBoundイベントをインターセプトします。個人オブジェクトの唯一のプロパティが名前であるため、バインディングは列ではなく名前を持つ行のみを作成するためです。個人オブジェクトのリストプロパティを強制的にバインドし、それぞれの列を作成するようにバインディングを強制する方法はあります。
解決
グリッドのデータソースとしてDataTableを使用してこれを解決できました。きれいなオブジェクトからDataTableに移動するというアイデアは好きではありませんが、必要な動的バインディングのサポートを提供します。友達オブジェクトを変更して、いくつかのコンストラクタを作成しました。これにより、静的コードの宣言をクリーンアップできましたが、実装には必要ないかもしれません。
基本的な考え方は、考えられるすべての友達をステップスルーし、その名前をDataTableのDataColumnとして追加し、すべての人物オブジェクトとそれぞれの友達のデータを入力することです。これはおそらくallPersonオブジェクトの1回の繰り返しで動作するように記述できますが、コードを読みやすくするために2回の繰り返しをお勧めします。
このソリューションはc#3.5向けに記述されていますが、静的データ宣言を変更することで古いバージョン用に変換できます。これがお役に立てば幸いです。
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// setup your person object with static data for testing
List<person> allPerson = new List<person>()
{
new person()
{
name = "Dan",
age = 21,
allMyFriends = new List<friend>() { new friend("James"), new friend("John"), new friend("Matt") }
},
new person()
{
name = "James",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan"), new friend("Matt"), new friend("Tom") }
},
new person()
{
name = "John",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan") }
},
new person()
{
name = "Matt",
age = 21,
allMyFriends = new List<friend>() { new friend("Dan"), new friend("James") }
},
new person()
{
name = "Tom",
age = 21,
allMyFriends = new List<friend>() { new friend("James") }
}
};
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Age");
foreach (person p in allPerson)
{
// step through each person and look at their friends
foreach (friend f in p.allMyFriends)
{
// look to see if this friend has a column already
if (!dt.Columns.Contains(f.name))
{
dt.Columns.Add(f.name);
}
}
}
foreach (person p in allPerson)
{
// create the datarow that represents the person
System.Data.DataRow dr = dt.NewRow();
dr["Name"] = p.name;
dr["Age"] = p.age;
// find the friends and mark them
foreach (friend f in p.allMyFriends)
{
dr[f.name] = "X";
}
dt.Rows.Add(dr);
}
// fill the list
this.Grid.DataSource = dt;
this.Grid.DataBind();
}
}
public class person
{
public string name;
public int age;
public List<friend> allMyFriends = new List<friend>();
}
public class friend
{
public string name;
public string address;
public friend()
{
}
public friend(string name)
{
this.name = name;
}
public friend(string name, string address)
{
this.name = name;
this.address = address;
}
}
編集: これがどのようにレンダリングされるかを追加するのを忘れました。
-------------------------------------------------
| Name | Age | James | John | Matt | Dan | Tom |
-------------------------------------------------
| Dan | 21 | X | X | X | | |
| James | 21 | | | X | X | X |
| John | 21 | | | | X | |
| Matt | 21 | X | | | X | |
| Tom | 21 | X | | | | |
-------------------------------------------------
他のヒント
GridViewでマトリックス/クロスタブを表示しようとしているようです。これと互換性のある形式でデータを取得する方が簡単な場合があります。 SQLサーバーを使用している場合は、クロス集計クエリの作成を検討できます。
現在のフォームのオブジェクトを操作する必要がある場合は、開始する前に友人の結合リストを作成すると、列リストを提供することもできます。その後、各列を関数呼び出しにバインドして、行のフレンドリストで列の人を見つけようとすることができます。
美しくありませんが、動作する可能性があります...
同様の「ネストされたバインディング」の質問に対する私の回答をご覧くださいこちら。
RowDataBoundイベントハンドラを使用して、複雑なバインドを行うこともできます。
次を使用:
DataBinder.Eval(Container.DataItem、&quot; PPP.PPP&quot;)