none
ListBoxへLINQを使って、文字列を加工しながらデータバインドする方法 RRS feed

  • 質問

  • ADO.NET エンティティデータモデルを使って、LINQ から直接リストボックス(ListBox)へデータバインドする方法を探しています。

    Dim ent As New SampleDBEntities
    ' 更新対象のレコードを検索する
    Dim q = From t In ent.商品
    		Select t.商品名, t.単価
    ' 結果を表示する
    ListBox1.DataSource = q.ToList()
    
    

    のように、Select 句で、二つの列(プロパティ)を並べると、{ 商品名=..., 単価=... } のように表示されてしまうので、これを「商品名 単価(円)」のようにしたいのですが、なにか簡単な方法はないでしょうか?

    ListBox の DataSource はデフォルトで ToString を使うので、ToString をオーバーライトしたクラスを使って new すればよいのですが、New With を使って匿名クラスを使う方法があれば、ベターなのですが。

    2013年6月10日 1:47

回答

  • 結果的に、下記の2つの方法で書けることがわかりました。

    ■むりやりCTypeでキャストする
    VB.NET 専用ですが、integerからStringへの自動キャストを利用しています。

    Dim ent As New SampleDBEntities
    ' 更新対象のレコードを検索する
    Dim q = From t In ent.商品
            Select t.商品名 + " " + CType(t.単価, String) + "円"
    ListBox1.DataSource = q.ToList
    


    ■Formatイベントハンドラを利用する
    trapemiya さんの Format イベントハンドラを使う方法
    こっちのほうは、String.Format を使えるので成形しやすいかも。

    Dim ent As New SampleDBEntities
    ' 更新対象のレコードを検索する
    Dim q = From t In ent.商品
            Select t.商品名, t.単価
    ' 結果を表示する
    ListBox1.FormattingEnabled = True
    AddHandler ListBox1.Format,
        Sub(s, ee) ee.Value = String.Format("{0} {1}円", ee.Value.商品名, ee.Value.単価)
    ListBox1.DataSource = q.ToList


    2013年6月11日 4:35
  • 参考までですが、ListBoxのFormatイベントハンドラでいろいろと加工ができますので、LINQと組み合わせたり、あるいやLINQを全く使わずにFormatイベントハンドラ単体で処理することができます。

    (参考)以下のページのFormatイベントハンドラ

    DisplayMemberとValueMemberプロパティについて
    http://dobon.net/vb/dotnet/control/tbdisplaymember.html


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク moonmileMVP 2013年6月11日 4:35
    2013年6月10日 5:08
    モデレータ

すべての返信

  • リストボックスの DisplayMember プロパティで実現できませんか?

    http://msdn.microsoft.com/ja-jp/library/system.windows.forms.listcontrol.displaymember(v=vs.80).aspx

    2013年6月10日 2:43
  • 今回のケース(商品名と単価を連結)だと、DisplayMemberよりLinqのSelect句で生成した方が良いと思います。

    Select t.商品名, t.単価
    の部分を

    Select t.商品名 + " " + t.単価.ToString() + "(円)"

    とかでどうでしょう。

    (Listにするのであれば、文字数制御をして綺麗に整えるなどは必要かと思いますが・・・)

    2013年6月10日 2:58
  • 参考までですが、ListBoxのFormatイベントハンドラでいろいろと加工ができますので、LINQと組み合わせたり、あるいやLINQを全く使わずにFormatイベントハンドラ単体で処理することができます。

    (参考)以下のページのFormatイベントハンドラ

    DisplayMemberとValueMemberプロパティについて
    http://dobon.net/vb/dotnet/control/tbdisplaymember.html


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク moonmileMVP 2013年6月11日 4:35
    2013年6月10日 5:08
    モデレータ
  • 試すとわかるのですが、残念ながら LINQ to Entities では、ToString が使えません。同じく、String.Format が使えないので、そこが苦労どころなのです。。。

    2013年6月11日 4:30
  • 結果的に、下記の2つの方法で書けることがわかりました。

    ■むりやりCTypeでキャストする
    VB.NET 専用ですが、integerからStringへの自動キャストを利用しています。

    Dim ent As New SampleDBEntities
    ' 更新対象のレコードを検索する
    Dim q = From t In ent.商品
            Select t.商品名 + " " + CType(t.単価, String) + "円"
    ListBox1.DataSource = q.ToList
    


    ■Formatイベントハンドラを利用する
    trapemiya さんの Format イベントハンドラを使う方法
    こっちのほうは、String.Format を使えるので成形しやすいかも。

    Dim ent As New SampleDBEntities
    ' 更新対象のレコードを検索する
    Dim q = From t In ent.商品
            Select t.商品名, t.単価
    ' 結果を表示する
    ListBox1.FormattingEnabled = True
    AddHandler ListBox1.Format,
        Sub(s, ee) ee.Value = String.Format("{0} {1}円", ee.Value.商品名, ee.Value.単価)
    ListBox1.DataSource = q.ToList


    2013年6月11日 4:35
  • 試すとわかるのですが、残念ながら LINQ to Entities では、ToString が使えません。同じく、String.Format が使えないので、そこが苦労どころなのです。。。

    嘘を書いてしまったかと思いあらためて再度確認しましたが、どちらも使えましたよ。

    以下検証ソースです。

    Public Class Form1
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Dim list As New List(Of Entity)
            For index = 1 To 10
                Dim item As New Entity
                item.商品名 = "商品名" + index.ToString()
                item.単価 = index
                list.Add(item)
            Next
    
            Dim listBox As New ListBox()
            'listBox.DataSource = (From item In list _
            '                      Select item.商品名 + " " + item.単価.ToString() + "円").ToList()
            listBox.DataSource = (From item In list _
                                  Select String.Format("{0} {1}円", item.商品名, item.単価.ToString())).ToList()
            Me.Controls.Add(listBox)
        End Sub
    End Class
    
    Public Class Entity
        Public Sub New()
    
        End Sub
    
        Public Property 商品名() As String
        Public Property 単価() As Integer
    
    End Class

    実行結果

    2013年6月11日 11:13
  • いやいや、普通の List では ToString が使えるのですが、「LINQ to Entities 」だと使えないのですよ。


    SQL Server で適当なテーブルを作って、ADO.NET Entity Data Model で試してみてください。

    なぜ使えないのかは、謎です...

    2013年6月11日 13:35
  • aviator__ さんの回答で思いついたのですが、

    Dim ent As New SampleDBEntities
    ' 表示対象のレコードを検索する
    Dim q = From t In ent.商品.ToList
    		 Select String.Format("{0} {1}円", t.商品名, t.単価)
    ListBox1.DataSource = q.ToList
    

    な風にして、ent.商品.ToList で List に変換してから整形というのありですね。

    直接 ToList してしまうと全件が対象になってしまうので、Where 句で絞ったあとに ToList すればフォーマットできる。実際、ListBox に入れるのは絞ったあとの件数になるので、このほうが素直かもしれません。


    2013年6月11日 13:44
  • すいません、前提条件を見逃してました。

    2013年6月11日 23:46