2008-09-14 25 views
43

ListBoxのようなコントロールが文字列を含む必要がないことをまだ認識していない人のための例を作っています。彼は書式設定された文字列を格納していて、複雑な解析フープを飛び越してListBoxからデータを取り戻しました。私は彼にもっと良い方法があることを示したいと思います。ListBoxでアイテムテキストを更新するにはどうすればよいですか?

オブジェクトがListBoxに保存されていて、ToStringに影響する値を更新すると、ListBoxは更新されません。私はRefreshUpdateをコントロールに呼び出してみましたが、どちらも機能しません。ここで私が使用している例のコードは、それがフォーム上にリストボックスとボタンをドラッグする必要があります、です:私は、おそらく問題のフィールドを使用していたとをINotifyPropertyChangedの実装しようとしたことを考え

Public Class Form1 

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs) 
     MyBase.OnLoad(e) 

     For i As Integer = 1 To 3 
      Dim tempInfo As New NumberInfo() 
      tempInfo.Count = i 
      tempInfo.Number = i * 100 
      ListBox1.Items.Add(tempInfo) 
     Next 
    End Sub 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     For Each objItem As Object In ListBox1.Items 
      Dim info As NumberInfo = DirectCast(objItem, NumberInfo) 
      info.Count += 1 
     Next 
    End Sub 
End Class 

Public Class NumberInfo 

    Public Count As Integer 
    Public Number As Integer 

    Public Overrides Function ToString() As String 
     Return String.Format("{0}, {1}", Count, Number) 
    End Function 
End Class

が、これを何の効果もありませんでした。 (私がフィールドを使用している理由は、それが例であり、私が主張しているトピックとは何の関係もない数十の行を追加する気がしないからです)。

正直言って私は以前のような場所にあるアイテム。過去に私はアイテムを編集するのではなく、アイテムを追加/削除していました。だから私はこの仕事をする方法がわからないことに気付かなかった。

私は何が欠けていますか?

答えて

24

BindingListは、バインディング自体の更新を処理します。

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace TestBindingList 
{ 
    public class Employee 
    { 
     public string Name { get; set; } 
     public int Id { get; set; } 
    } 

    public partial class Form1 : Form 
    { 
     private BindingList<Employee> _employees; 

     private ListBox lstEmployees; 
     private TextBox txtId; 
     private TextBox txtName; 
     private Button btnRemove; 

     public Form1() 
     { 
      InitializeComponent(); 

      FlowLayoutPanel layout = new FlowLayoutPanel(); 
      layout.Dock = DockStyle.Fill; 
      Controls.Add(layout); 

      lstEmployees = new ListBox(); 
      layout.Controls.Add(lstEmployees); 

      txtId = new TextBox(); 
      layout.Controls.Add(txtId); 

      txtName = new TextBox(); 
      layout.Controls.Add(txtName); 

      btnRemove = new Button(); 
      btnRemove.Click += btnRemove_Click; 
      btnRemove.Text = "Remove"; 
      layout.Controls.Add(btnRemove); 

      Load+=new EventHandler(Form1_Load); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      _employees = new BindingList<Employee>(); 
      for (int i = 0; i < 10; i++) 
      { 
       _employees.Add(new Employee() { Id = i, Name = "Employee " + i.ToString() }); 
      } 

      lstEmployees.DisplayMember = "Name"; 
      lstEmployees.DataSource = _employees; 

      txtId.DataBindings.Add("Text", _employees, "Id"); 
      txtName.DataBindings.Add("Text", _employees, "Name"); 
     } 

     private void btnRemove_Click(object sender, EventArgs e) 
     { 
      Employee selectedEmployee = (Employee)lstEmployees.SelectedItem; 
      if (selectedEmployee != null) 
      { 
       _employees.Remove(selectedEmployee); 
      } 
     } 
    } 
} 
+0

これは現在受け入れられている回答よりも実際には機能しません。壮大!あなたの投稿を編集して例を挙げました。 – OwenP

+1

あなたは実際にそれをさらに改善することができました。親と子のバインディングは、_SelectedIndexChangedイベントハンドラなしで行うことができるコントロールに適用できます。私は正確なコードを忘れています..... :( – Quibblesome

+0

私は、SelectedIndexChangedイベントハンドラを削除し、Loadハンドラで2行の新しい行に置き換えて、例を更新しました:) – Quibblesome

9

データソースプロパティとリストボックスのデータソースプロパティの間にBindingSourceオブジェクトを使用します。次にそれをリフレッシュしてください。

更新追加例。

そのよう

:私はvb.netについて多くを知らないが、C#で使用すると、データソースを使用する必要があり、その後、トリックを行うだろうlistbox.bind()を呼び出すことによって、それをバインドする

Public Class Form1 

    Private datasource As New List(Of NumberInfo) 
    Private bindingSource As New BindingSource 

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs) 
     MyBase.OnLoad(e) 

     For i As Integer = 1 To 3 
      Dim tempInfo As New NumberInfo() 
      tempInfo.Count = i 
      tempInfo.Number = i * 100 
      datasource.Add(tempInfo) 
     Next 
     bindingSource.DataSource = datasource 
     ListBox1.DataSource = bindingSource 
    End Sub 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     For Each objItem As Object In datasource 
      Dim info As NumberInfo = DirectCast(objItem, NumberInfo) 
      info.Count += 1 
     Next 
     bindingSource.ResetBindings(False) 
    End Sub 
End Class 

Public Class NumberInfo 

    Public Count As Integer 
    Public Number As Integer 

    Public Overrides Function ToString() As String 
     Return String.Format("{0}, {1}", Count, Number) 
    End Function 
End Class 
+0

エクセレントを更新します。何らかの理由で、WinFormsのデータバインディングは、私がWPFでどれくらい使っても解決策として私のところに飛び出すことはありません。 – OwenP

+0

これは以前よりも楽しいものでした。次のようなものがあります。 ((CurrencyManager)this.BindingContext [ListBox1])。Refresh(); "隠された"オブジェクトをBindingContextから取得し、それを通貨マネージャーにキャストします。 これはVB.NETでこれを行ったことのないC#ですが。 – Quibblesome

+0

これは良い答えですが、最終的にBindingList を使用するというジェノの提案により、作業が少なくなります。 – OwenP

-1

+2

インターネット用のものです。この人はWinFormに興味があります。 – Quibblesome

1

ListBoxから派生した場合は、呼び出すことができるRefreshItemで保護されたメソッドがあります。自分のタイプでこのメソッドを再公開するだけです。

public class ListBox2 : ListBox { 
    public void RefreshItem2(int index) { 
     RefreshItem(index); 
    } 
} 

次に、独自のタイプ(この場合はListBox2)を使用するようにデザイナーファイルを変更します。

32

更新するリストボックスが必要な場合は、このクラスを使用します。

インデックス内のオブジェクトを更新してから、インデックスを使用できるかどうかに応じて、含まれているメソッドのいずれかを呼び出します。リストに含まれているオブジェクトを更新しているのにインデックスを持っていない場合は、RefreshItemsを呼び出してすべてのアイテムを更新する必要があります。

public class RefreshingListBox : ListBox 
{ 
    public new void RefreshItem(int index) 
    { 
     base.RefreshItem(index); 
    } 

    public new void RefreshItems() 
    { 
     base.RefreshItems(); 
    } 
} 
+0

注意: 'RefreshItem'は、' DisplayMember'プロパティが設定されている場合にのみ機能します。 –

0

これはちょっと専門的ではありませんが、機能します。 アイテムを削除して追加しました(もう一度選択しました)。 リストは「表示され、変更された」プロパティに従って並べ替えられました。副作用は追加イベント(インデックス変更)が発生することです。

if (objLstTypes.SelectedItem != null) 
{ 
PublisherTypeDescriptor objType = (PublisherTypeDescriptor)objLstTypes.SelectedItem; 
objLstTypes.Items.Remove(objType); 
objLstTypes.Items.Add(objType); 
objLstTypes.SelectedItem = objType; 
} 
+0

なぜダウン投票? – nawfal

+0

これは、常に選択した項目をListBoxの最後に配置します。 –

-3

objLstTypesが 使用 objLstTypes.ItemsあなたのListBoxの名前である場合。リフレッシュ(); これがうまくいくと思います...

+0

更新方法はありません。 –

29
lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem; 
+5

これは実際に有効な答えです! – nawfal

+3

これは私の投票を得る!シンプルな、新しいクラスやコードの段落を追加することなく行うことができます。これは私が必要だったすべてでした。 – Rob

+1

ファンタスティック - シンプルで、仕事が終わった、ありがとう! –

16
typeof(ListBox).InvokeMember("RefreshItems", 
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, 
    null, myListBox, new object[] { }); 
+0

私はこれが便利であることを発見しました。リストボックスを動的にリフレッシュさせるために使用できます –

0

あなたは次のようにdrawメソッドを使用する場合:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e) 
{ 
    e.DrawBackground(); 
    e.DrawFocusRectangle(); 

    Sensor toBeDrawn = (listBox1.Items[e.Index] as Sensor); 
    e.Graphics.FillRectangle(new SolidBrush(toBeDrawn.ItemColor), e.Bounds); 
    e.Graphics.DrawString(toBeDrawn.sensorName, new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold), new SolidBrush(Color.White),e.Bounds); 
} 

センサーが私のクラスです。

私はどこかでクラスColorを変更するのであれば、あなたは単にそれを更新することができます

int temp = listBoxName.SelectedIndex; 
listBoxName.SelectedIndex = -1; 
listBoxName.SelectedIndex = temp; 

そしてColorは、ちょうど別のソリューション:)