2011-08-18 49 views
1

我很好奇是否有一種簡單的方法將類的屬性綁定到CheckedListBox的各個項目。有幾個組件(Telerik/DevExpress)提供PropertyEditor網格,但是我希望在CheckedListBox中完成它。CheckedListBox和綁定對象屬性到項目

IE:

public class MyItem 
{ 
    public bool Property1 
    { 
     get; 
     set; 
    } 

    public bool Property2 
    { 
     get; 
     set; 
    } 

    public bool Property3 
    { 
     get; 
     set; 
    } 
} 

和添加項目到CheckedListBox的時候,我想有某種方法,讓我做的事:

this.AddCheckListBoxItem("Property A", this.myItem.Property1); 
this.AddCheckListBoxItem("Property B", this.myItem.Property2); 
this.AddCheckListBoxItem("Property C", this.myItem.Property3); 

第一個參數是顯示名稱在CheckedListBox中。

然後,在對checkstate所做的任何更改期間,bool值將自動更新而無需進一步的代碼。

感謝,

馬克

+0

我有一個如何做到這一點的想法它將需要我幾分鐘來實現它,但你需要使用我認爲的反思。 – Jethro

+0

我知道如何使用反射來完成它,但我不想僅僅爲此使用反射。試圖想出另一種方法。 – mservidio

+0

不這麼認爲。爲什麼你討厭使用反射? – Jethro

回答

0

我已經使用@Jethro建議的反射創建了一個解決方案。我在類定義中使用了泛型,但是我沒有實現任何使用它們的東西。總結一下,基本上使用反射,我綁定了一個單獨的對象,它是標準CheckedListBox中單個項目的布爾屬性。這很好,因爲它不需要編寫代碼來設置屬性值並在保存數據時獲取它們,因爲反射會照顧到這一點。

我創建了一個Form,並添加了一個CheckedListBox和一個按鈕。這是代碼的一面。

using System; 
using System.Linq; 
using System.Reflection; 
using System.Windows.Forms; 

/// <summary> 
/// The main form. 
/// </summary> 
public partial class Form1 : Form 
{ 
    /// <summary> 
    /// The checked list box property helper. 
    /// </summary> 
    private CheckedListBoxPropertyHelper<MyItem> helper; 

    /// <summary> 
    /// My object to bind to the checked list box. 
    /// </summary> 
    private MyItem myObjectDataSource; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Form1"/> class. 
    /// </summary> 
    public Form1() 
    { 
     this.InitializeComponent(); 

     this.myObjectDataSource = new MyItem(); 
     this.helper = new CheckedListBoxPropertyHelper<MyItem>(this.checkedListBox1, this.myObjectDataSource, true); 

     this.helper.AddCheckListBoxItem(new CheckedPropertyItem("Property One", "Property1")); 
     this.helper.AddCheckListBoxItem(new CheckedPropertyItem("Property Two", "Property2")); 
     this.helper.AddCheckListBoxItem(new CheckedPropertyItem("Property Three", "Property3")); 
    } 

    /// <summary> 
    /// Handles the Click event of the Button1 control. 
    /// </summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> 
    private void Button1_Click(object sender, EventArgs e) 
    { 
     // In the constructor 
     // if we instantiated: this.helper = new CheckedListBoxPropertyHelper<MyItem>(this.checkedListBox1, this.myObjectDataSource, true); 
     // as: this.helper = new CheckedListBoxPropertyHelper<MyItem>(this.checkedListBox1, this.myObjectDataSource, false); 
     // changing the last bindImmediate property to false, the changes to the checkboxes wouldn't take effect immediately 
     // on the underlying object, you need to call this.helper.CommitChanges() at which point the changes 
     // will be made to the datasource object. 

     // this.helper.CommitChanges(); 

     Console.WriteLine(this.myObjectDataSource.Property1.ToString()); 
     Console.WriteLine(this.myObjectDataSource.Property2.ToString()); 
     Console.WriteLine(this.myObjectDataSource.Property3.ToString()); 
    } 
} 

/// <summary> 
/// My item. 
/// </summary> 
public class MyItem 
{ 
    /// <summary> 
    /// Gets or sets a value indicating whether this <see cref="MyItem"/> is property1. 
    /// </summary> 
    /// <value><c>true</c> if property1; otherwise, <c>false</c>.</value> 
    public bool Property1 
    { 
     get; 
     set; 
    } 

    /// <summary> 
    /// Gets or sets a value indicating whether this <see cref="MyItem"/> is property2. 
    /// </summary> 
    /// <value><c>true</c> if property2; otherwise, <c>false</c>.</value> 
    public bool Property2 
    { 
     get; 
     set; 
    } 

    /// <summary> 
    /// Gets or sets a value indicating whether this <see cref="MyItem"/> is property3. 
    /// </summary> 
    /// <value><c>true</c> if property3; otherwise, <c>false</c>.</value> 
    public bool Property3 
    { 
     get; 
     set; 
    } 
} 

/// <summary> 
/// The checked list box property helper. This binds datasource properties to checkedlistbox items. 
/// </summary> 
public class CheckedListBoxPropertyHelper<T> where T : class 
{ 
    /// <summary> 
    /// The checked list box. 
    /// </summary> 
    private CheckedListBox checkedListBox; 

    /// <summary> 
    /// The property info. 
    /// </summary> 
    private PropertyInfo[] PropertyInfo; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="CheckedListBoxPropertyHelper"/> class. 
    /// </summary> 
    /// <param name="checkedListBox">The checked list box.</param> 
    /// <param name="dataSource">The data source.</param> 
    /// <param name="bindImmediate">if set to <c>true</c> [bind immediate].</param> 
    public CheckedListBoxPropertyHelper(CheckedListBox checkedListBox, T dataSource, bool bindImmediate) 
    { 
     this.checkedListBox = checkedListBox; 
     this.DataSource = dataSource; 
     this.PropertyInfo = this.DataSource.GetType().GetProperties(); 
     this.BindImmediate = bindImmediate; 
     this.checkedListBox.ItemCheck += new ItemCheckEventHandler(CheckedListBox_ItemCheck); 
    } 

    /// <summary> 
    /// The data source. 
    /// </summary> 
    public T DataSource 
    { 
     get; 
     private set; 
    } 

    /// <summary> 
    /// Gets or sets a value indicating whether to [bind immediately] to the datasource object. 
    /// </summary> 
    /// <value><c>true</c> if [bind immediately]; otherwise, <c>false</c>.</value> 
    public bool BindImmediate 
    { 
     get; 
     set; 
    } 

    /// <summary> 
    /// Commits the changes. 
    /// </summary> 
    public void CommitChanges() 
    { 
     if (!this.BindImmediate) 
     { 
      for (int i = 0; i < this.checkedListBox.Items.Count; i++) 
      { 
       CheckedPropertyItem checkedItem = this.checkedListBox.Items[i] as CheckedPropertyItem; 
       this.SetChecked(this.checkedListBox.GetItemChecked(i), checkedItem); 
      } 
     } 
     else 
     { 
      throw new InvalidOperationException("You cannot commit changes when bind immediate is on."); 
     } 
    } 

    /// <summary> 
    /// Adds the check list box item. 
    /// </summary> 
    /// <param name="item">The item.</param> 
    public void AddCheckListBoxItem(CheckedPropertyItem item) 
    { 
     PropertyInfo info = this.GetPropertyInfo(item.PropertyName); 
     bool isChecked = false; 

     if (info != null) 
     { 
      isChecked = (bool)info.GetValue(this.DataSource, null); 
     } 

     this.checkedListBox.Items.Add(item, isChecked); 
    } 

    /// <summary> 
    /// Handles the ItemCheck event of the CheckedListBox control. 
    /// </summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The <see cref="System.Windows.Forms.ItemCheckEventArgs"/> instance containing the event data.</param> 
    private void CheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e) 
    { 
     if (BindImmediate) 
     { 
      CheckedListBox clb = sender as CheckedListBox; 
      CheckedPropertyItem checkedItem = clb.Items[e.Index] as CheckedPropertyItem; 

      this.SetChecked(
       e.NewValue == CheckState.Checked ? true : false, 
       checkedItem); 
     } 
    } 

    /// <summary> 
    /// Sets the checked. 
    /// </summary> 
    /// <param name="isChecked">if set to <c>true</c> [is checked].</param> 
    /// <param name="clb">The CLB.</param> 
    private void SetChecked(bool isChecked, CheckedPropertyItem item) 
    { 
     PropertyInfo info = this.GetPropertyInfo(item.PropertyName); 

     if (info.CanWrite) 
     { 
      info.SetValue(this.DataSource, isChecked, null); 
     } 
    } 

    /// <summary> 
    /// Gets the property info. 
    /// </summary> 
    /// <param name="propertyName">Name of the property.</param> 
    /// <returns></returns> 
    private PropertyInfo GetPropertyInfo(string propertyName) 
    { 
     return this.PropertyInfo 
      .Where(c => c.Name == propertyName) 
      .SingleOrDefault(); 
    } 
} 

/// <summary> 
/// Checked Property Item binding. 
/// </summary> 
public class CheckedPropertyItem 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="CheckedPropertyItem"/> class. 
    /// </summary> 
    /// <param name="title">The title.</param> 
    /// <param name="propertyName">Name of the property.</param> 
    public CheckedPropertyItem(string title, string propertyName) 
    { 
     this.Title = title; 
     this.PropertyName = propertyName; 
    } 

    /// <summary> 
    /// Gets or sets the title. 
    /// </summary> 
    /// <value>The title.</value> 
    public string Title 
    { 
     get; 
     private set; 
    } 

    /// <summary> 
    /// Gets the name of the property. 
    /// </summary> 
    public string PropertyName 
    { 
     get; 
     private set; 
    } 

    /// <summary> 
    /// Returns a <see cref="System.String"/> that represents this instance. 
    /// </summary> 
    /// <returns>A <see cref="System.String"/> that represents this instance.</returns> 
    public override string ToString() 
    { 
     return this.Title; 
    } 
} 
+0

看起來不錯。祝賀夥計。只有一個不是很重要的小改變,我會做出。緩存GetPropertyInfo方法的PropertyInfo。除了那令人敬畏的工作! – Jethro

+0

我更新了它。我爲構造函數中的數據源對象獲取PropertyInfo []並進行存儲。 – mservidio

+0

我已經將BindImmediate屬性添加到幫助程序中。如果它在構造函數中設置爲false,則需要調用CommitChanges()以將檢查狀態更改應用於基礎數據源。如果設置爲true,則在更改檢查狀態後立即反映更改。 – mservidio

1

目前沒有任何容易/簡單的方式來獲得你正在尋找後的功能。 正如在評論中,我能想到的最接近的解決方案就是使用反射。

如果你設法建立一個具有這個功能的輔助類,請在這裏發帖,因爲我也會發現有用的。

+0

我已經發布了執行此功能的代碼。看一看,讓我知道你的想法。有幾個部分可以加強,但這是我認爲的一般想法。 – mservidio