Как привязать флажок пользовательского элемента управления - PullRequest
1 голос
/ 27 октября 2011

У меня некоторое время были проблемы с пользовательским элементом управления флажком, и я опубликовал этот Вопрос ... Похоже, что проблема не связана с событиями.

Пользовательский элемент управления представляет собой групповое поле с флажком.Когда флажок установлен в ложь, все элементы управления группы должны быть отключены.Звучит просто, но проблема в том, что когда внутренний элемент управления теряет фокус, запускается событие проверенного изменения.

После еще нескольких копаний, я думаю, я сузил его до привязки свойства selected к другому объекту.,Когда привязка включена, она работает неправильно, но с удаленной привязкой все работает, как ожидалось.

Я не уверен, как решить проблему сейчас, когда она была обнаружена.

Кто-нибудь может помочь?

Вот код из моеготестовое приложение -

Форма: enter image description here

Код формы:

public partial class Form1 : Form
{
    TestProperties m_TP;

    public Form1()
    {
        // Create instance of TestProperties
        m_TP = new TestProperties();

        InitializeComponent();

        BindControls();
    }

    private void BindControls()
    {
        // Bind the values to from the controls in the group to the properties class

        // When the line below is commented out the control behaves normally
        //this.checkedGroupBox1.DataBindings.Add("Checked", m_TP, "GroupChecked");
        this.numericUpDown1.DataBindings.Add("Value", m_TP, "SomeNumber");
        this.textBox1.DataBindings.Add("Text", m_TP, "SomeText");
        this.checkBox1.DataBindings.Add("Checked", m_TP, "BoxChecked");

        // Bind the values of the properties to the lables
        this.label4.DataBindings.Add("Text", m_TP, "GroupChecked");
        this.label5.DataBindings.Add("Text", m_TP, "SomeNumber");
        this.label6.DataBindings.Add("Text", m_TP, "SomeText");
        this.label8.DataBindings.Add("Text", m_TP, "BoxChecked");
    }
}

Класс хранения свойства:

class TestProperties
{
    public bool GroupChecked { get; set; }
    public decimal SomeNumber { get; set; }
    public string SomeText { get; set; }
    public bool BoxChecked { get; set; }

    public TestProperties()
    {
        GroupChecked = false;
        SomeNumber = 0;
        SomeText = string.Empty;
        BoxChecked = true;
    }
}

РЕДАКТИРОВАТЬ: Вот источник для моего пользовательского элемента управления:

/// <summary>
/// Custom control to create a checked group box.
/// Enables / disables all controls within the group depending upon the state of the check box
/// </summary>
public class CheckedGroupBox : System.Windows.Forms.GroupBox
{
    #region Private Member Variables
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Checkbox to enable / disable the controls within the group
    /// </summary>
    private CheckBox chkBox;

    /// <summary>
    /// Label for the group box which is set to autosize
    /// </summary>
    private Label lblDisplay;
    #endregion

    /// <summary>
    ///  Default constructor for the control
    /// </summary>
    public CheckedGroupBox()
    {
        // This call is required by the Windows Form Designer.
        InitializeComponent();

        // The text of these controls should always be empty.
        this.Text = "";
        this.chkBox.Text = "";
    }

    #region Events & Delegates

    /// <summary>
    /// Event to forward the change in checked flag
    /// </summary>
    public event EventHandler CheckedChanged;

    /// <summary>
    /// Event to forward the change in checked state of the checkbox
    /// </summary>
    public event EventHandler CheckStateChanged;

    private void chkBox_CheckedChanged(object sender, EventArgs e)
    {
        // Disable the controls within the group
        foreach (Control ctrl in this.Controls)
        {
            if (ctrl.Name != "chkBox" && ctrl.Name != "lblDisplay")
            {
                ctrl.Enabled = this.chkBox.Checked;
            }
        }

        // Now forward the Event from the checkbox
        if (this.CheckedChanged != null)
        {
            this.CheckedChanged(sender, e);
        }
    }

    private void chkBox_CheckStateChanged(object sender, EventArgs e)
    {
        // Forward the Event from the checkbox
        if (this.CheckStateChanged != null)
        {
            this.CheckStateChanged(sender, e);
        }
    }

    #endregion

    #region Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.chkBox = new System.Windows.Forms.CheckBox();
        this.lblDisplay = new System.Windows.Forms.Label();
        this.SuspendLayout();
        // 
        // chkBox
        // 
        this.chkBox.Location = new System.Drawing.Point(8, 0);
        this.chkBox.Name = "chkBox";
        this.chkBox.Size = new System.Drawing.Size(16, 16);
        this.chkBox.TabIndex = 0;
        this.chkBox.CheckStateChanged += new System.EventHandler(this.chkBox_CheckStateChanged);
        this.chkBox.CheckedChanged += new System.EventHandler(this.chkBox_CheckedChanged);
        // 
        // lblDisplay
        // 
        this.lblDisplay.AutoSize = true;
        this.lblDisplay.Location = new System.Drawing.Point(24, 0);
        this.lblDisplay.Name = "lblDisplay";
        this.lblDisplay.Size = new System.Drawing.Size(97, 13);
        this.lblDisplay.TabIndex = 1;
        this.lblDisplay.Text = "CheckedGroupBox";
        // 
        // CheckedGroupBox
        // 
        this.BackColor = System.Drawing.Color.AliceBlue;
        this.Controls.Add(this.chkBox);
        this.Controls.Add(this.lblDisplay);
        this.Size = new System.Drawing.Size(100, 100);
        this.ResumeLayout(false);
        this.PerformLayout();

    }
    #endregion

    #region Public properties

    [Bindable(true), Category("Appearance"), DefaultValue("Check Group Text")]
    public override string Text
    {
        get{ return this.lblDisplay.Text; }
        set{ this.lblDisplay.Text = value; }
    }

    [Bindable(true), Category("Appearance"), DefaultValue("Checked")]
    public System.Windows.Forms.CheckState CheckState
    {
        get{ return this.chkBox.CheckState; }
        set
        { 
            this.chkBox.CheckState = value; 

            foreach( Control ctrl in this.Controls )
            {
                if( ctrl.Name != "chkBox" && ctrl.Name != "lblDisplay" )
                {
                    ctrl.Enabled = this.chkBox.Checked;
                }
            }
        }
    }

    [Bindable(true), Category("Appearance"), DefaultValue("True")]
    public bool Checked
    {
        get{ return this.chkBox.Checked; }
        set
        { 
            this.chkBox.Checked = value; 

            foreach( Control ctrl in this.Controls )
            {
                if( ctrl.Name != "chkBox" && ctrl.Name != "lblDisplay" )
                {
                    ctrl.Enabled = this.chkBox.Checked;
                }
            }
        }
    }

    [Bindable(true), Category("Behavior"), DefaultValue("False")]
    public bool ThreeState
    {
        get{ return this.chkBox.ThreeState; }
        set{ this.chkBox.ThreeState = value; }
    }

    #endregion

}

Ответы [ 3 ]

2 голосов
/ 28 октября 2011

Вам необходимо изменить метод BindControls следующим образом. Причина этого заключается в том, что по умолчанию элементы управления обновляются, чтобы отражать свойства m_TP, но при изменении их значений изменения не отражаются в m_TP (я полагаю, что события Leave вызывают повторное связывание элементов управления с источники данных). При добавлении параметра DataSourceUpdateMode изменения будут внесены в двух направлениях.

private void BindControls()
{
    // Bind the values to from the controls in the group to the properties class

    // When the line below is commented out the control behaves normally
    this.checkedGroupBox1.DataBindings.Add("Checked", m_TP, "GroupChecked", false, DataSourceUpdateMode.OnPropertyChanged);
    this.numericUpDown1.DataBindings.Add("Value", m_TP, "SomeNumber", false, DataSourceUpdateMode.OnPropertyChanged);
    this.textBox1.DataBindings.Add("Text", m_TP, "SomeText", false, DataSourceUpdateMode.OnPropertyChanged);
    this.checkBox1.DataBindings.Add("Checked", m_TP, "BoxChecked", false, DataSourceUpdateMode.OnPropertyChanged);

    // Bind the values of the properties to the lables
    this.label4.DataBindings.Add("Text", m_TP, "GroupChecked");
    this.label5.DataBindings.Add("Text", m_TP, "SomeNumber");
    this.label6.DataBindings.Add("Text", m_TP, "SomeText");
    this.label8.DataBindings.Add("Text", m_TP, "BoxChecked");
}
1 голос
/ 27 октября 2011

Во-первых, для правильной работы привязки вам необходимо реализовать INotifyPropertyChanged в классе хранения вашего свойства.Пожалуйста, посмотрите пример здесь

В вашей среде Visual Studio создайте новый источник данных, указывающий на тип «Объект».Выберите ваш класс TestProperties в качестве исходного объекта (если класс не отображается в списке, убедитесь, что вы собрали содержащую сборку, и ваш проект WinForm имеет ссылку на него).

Data Source Configuration Wizard

Теперь перетащите BindingSource из панели инструментов на свой пользовательский элемент управления.Задайте для свойства DataSource объекта BindingSource источник данных TestProperties, созданный на предыдущем шаге.

Теперь выберите групповое поле настраиваемого элемента управления и перейдите в раздел (DataBindings).Нажмите «...» в расширенном поле.Свяжите свойство «Enabled» настраиваемого элемента управления сеткой со свойством «BoxChecked» BindingSource.Все это можно сделать в конструкторе (или, если хотите, через код)

enter image description here

Привязать другие элементы WinForms в пользовательском элементе управления к соответствующим элементам класса TestProperties черезBindingSource.

Теперь представьте свойство в пользовательском элементе управления, чтобы вы могли привязать его к «родительской» форме.Убедитесь, что вы установили «DataSource» в BindingSource для нового ссылочного свойства.

    private TestProperties _properties;
    public TestProperties Properties
    {
        get { return _properties; }
        set
        {
            _properties = value;
            this.bindingSource1.DataSource = _properties;
        }
    }

    public UserControl1()
    {
        InitializeComponent();
    }

В родительской форме, в которой размещается элемент управления, у вас есть несколько вариантов.

1) Вы можете выполнить привязку непосредственно к классу TestProperties, предоставляемому UserControl, как вы это делали в приведенном выше примере

2) Вы можете повторить упражнение BindingSource, которое вы использовали для настройки привязки напользовательский элемент управления на родительском элементе управления и установите свойство DataSource нового BindingSource (в родительской форме) равным открытому свойству TestProperties элемента UserControl.

0 голосов
/ 27 октября 2011

Что-то вроде этого настолько близко, насколько я мог бы получить:

enter image description here

У меня явно нет кода для группового блока (с включенным флажком), поэтому я обошелся счто я мог.

Это достигается добавлением этого в верхний флажок:

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
   groupBox1.Enabled = ((CheckBox)(sender)).Checked;
}

Я также снова включил эту строку:

this.checkBox1.DataBindings.Add("Checked", m_TP, "GroupChecked");
...