2011-08-18 8 views
1

클래스의 속성을 CheckedListBox의 개별 항목에 바인딩하는 간단한 방법이 있는지 궁금합니다. PropertyEditor 그리드를 제공하는 몇 가지 구성 요소 (Telerik/DevExpress)가 있지만 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 내에서.

그런 다음 검사 상태가 변경되는 동안 부울 값은 자동으로 추가 코드없이 업데이트됩니다.

감사합니다,

마크

+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

현재 당신이 찾고있는 functionallity을 얻을 수있는 쉬운/간단한 방법이 없다. 코멘트에서와 같이 내가 생각할 수있는 가장 가까운 해결책은 리플렉션을 사용하는 것입니다.

이 functionallity가있는 도우미 클래스를 작성하는 경우 여기를 게시하여 유용하게 사용할 수 있습니다.

+0

이 기능을 수행하는 코드를 게시했습니다. 외모를 가지고 당신이 생각하는 것을 알려주십시오. 강화할 수있는 부분이 몇 가지 있습니다. 그러나 이것이 제가 생각하는 일반적인 생각입니다. – mservidio