2009-08-13 11 views
4

Dans Windows Forms (.NET 2.0, Visual Studio 2005 SP1): J'ai un DataSet typé, avec une colonne de type System.Boolean, qui est nullable et dont la valeur par défaut est DBNull. J'ai un Form, contenant un contrôle CheckBox que je veux lier à la valeur de la colonne précédente.Comment lier un CheckBox à un DbColumn de type booléen nullable?

  • J'ai essayé de lier la propriété Checked à la colonne via le concepteur: il fonctionne très bien, que si la valeur par défaut de la colonne est définie sur True ou False.
  • j'ai essayé de lier la propriété CheckState à la colonne par le concepteur, et fixer mes propres gestionnaires d'événements Format et Parse mais ils ne sont jamais appelés:

    b.Format+=delegate(object sender, ConvertEventArgs cevent) { 
        cevent.Value=DoFormat((CheckState)cevent.Value); // cf. end of the question 
    }; 
    b.Parse+=delegate(object sender, ConvertEventArgs cevent) { 
        cevent.Value=DoParse(cevent.Value); // cf. end of the question 
    }; 
    
  • J'ai essayé de créer une coutume Binding par exemple dans le code, veuillez joindre mes gestionnaires d'événements et l'ajouter aux CheckBox fixations: les gestionnaires d'événements sont encore jamais appelés ... se

    Binding b=new Binding("CheckState", _BindingSource, "MyColumn", false, DataSourceUpdateMode.OnPropertyChanged, DBNull.Value); 
    

À noter: une valeur DBNull n'est acceptable que si elle provient du DataSet (cela signifie que la valeur n'a jamais été définie). Mais l'utilisateur ne doit pouvoir définir que la valeur True ou False via le CheckBox.

Pour référence, voici le code de l'analyse syntaxique et de formatage méthodes:

internal static CheckState DoParse(object value) 
{ 
    if ((value==null) || (value is DBNull)) 
     return CheckState.Indeterminate; 

    bool v=Convert.ToBoolean(value); 
    return (v ? CheckState.Checked : CheckState.Unchecked); 
} 

internal static object DoFormat(CheckState value) 
{ 
    switch (value) 
    { 
    case CheckState.Checked: 
     return true; 
    case CheckState.Indeterminate: 
     return DBNull.Value; 
    case CheckState.Unchecked: 
     return false; 
    } 

    return null; 
} 
+0

J'ai ajouté des informations sur ** pourquoi cela fonctionne * à la fin de ma réponse. –

Répondre

7

Avez-vous essayé lier CheckBox.CheckState au DataColumn sans y attacher Parse et des événements de format ou de déconner avec la liaison?

Malheureusement, je n'ai pas une instance de Visual Studio 2005 disponible mais je rassemblai une forme rapide dans Visual Studio 2008 et il a fait exactement ce que vous avez spécifié:

Comme une note: une valeur DBNull est acceptable uniquement en provenance du DataSet (cela signifie que la valeur n'a jamais été définie). Mais l'utilisateur ne doit pouvoir définir la valeur à True ou False via le CheckBox.

Je peux être Parse, Format ou reliure obtenir de votre manière ou il se peut que Windows Forms se comporte différemment en 2008 qu'en 2005


Mise à jour le 18 août: Il fonctionne sur Visual Studio 2005 aussi bien à travers le concepteur et à travers le code. est ici le code qui le démontre travail:


using System; 
using System.Data; 
using System.Drawing; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 { 
    public partial class Form1 : Form { 
     DataTable table = new DataTable(); 
     public Form1() { 
      InitializeComponent(); 

      //Creates the table structure 
      table.Columns.Add("Name", typeof(string)); 
      table.Columns.Add("MyColumn", typeof(bool)); 

      //Populates the table with some stuff 
      for (int i = 0; i < 5; i++) { 
       table.Rows.Add(i.ToString()); 
      } 

      //Creates the controls and puts them on the form. 
      TextBox textBox = new TextBox(); 
      textBox.Location = new Point(10, 10); 
      textBox.DataBindings.Add("Text", table, "Name"); 

      CheckBox checkBox = new CheckBox(); 
      checkBox.Left = textBox.Left; 
      checkBox.Top = textBox.Bottom + 10; 

      //Without true on the last argument, it will not work properly. 
      checkBox.DataBindings.Add("CheckState", table, "MyColumn", true); 

      Button previous = new Button(); 
      previous.Text = ""; 
      next.Top = previous.Top; 
      next.Left = previous.Right + 5; 
      next.Click += new EventHandler(next_Click); 

      this.Controls.AddRange(new Control[] { textBox, checkBox, previous, next }); 
     } 

     void next_Click(object sender, EventArgs e) { 
      this.BindingContext[this.table].Position++; 
     } 

     void previous_Click(object sender, EventArgs e) { 
      this.BindingContext[this.table].Position--; 
     } 
    } 
} 


Mise à jour le 23 août:

Pourquoi cela fonctionne

de liaison a une méthode privée appelée formatObject qui est responsable de l'obtention une représentation de la valeur provenant de la source de données qui est appropriée pour être affichée sur le contrôle. Lorsque le formatage est activé, Binding.FormatObject() parcourt un chemin de code qui appelle les éventuels gestionnaires que vous avez pour l'événement Binding.Format. Si un gestionnaire modifie la valeur en cours de propagation de la source de données vers le contrôle via ConvertEventArgs.Value, cette valeur sera utilisée. Sinon, il appellera un formateur par défaut appelé FormatObject sur une classe interne appelée System.Windows.Forms.Formatter.

Les commentaires sur l'état du code source:

« Le vrai travail de conversion se produit à l'intérieur FormatObjectInternal() »

Les commentaires pour l'état FormatObjectInternal:

« Réalise quelques conversions cas spéciaux (par exemple Boolean to CheckState) "

A l'intérieur de FormatObjectInternal il vérifie si la valeur provenant de la source de données est nulle ou DBNull et si c'est le cas, il vérifie si le type de la propriété liée est de CheckState. Si tel est le cas, il renvoie CheckState.Indeterminate.

Comme vous pouvez le voir, il s'agit d'un cas si courant qu'il est surprenant que cela n'ait pas fonctionné sous Windows Forms 1.x. Heureusement, le fixe sur 2.0 et au-delà.

+0

Je pense que ça ferait mal à ma tête (beaucoup) de lier une donnée booléenne à un type énuméré (avec 3 valeurs possibles!), Mais je vais essayer quand même par curiosité ... – Mac

+0

J'ai essayé sur Visual Studio 2005 et travaillé aussi. À la fois via le concepteur et via le code. –

+0

Votre exemple fonctionne, mais n'est pas correct pour cette question. @Mac veut que "DBNull puisse être peuplé de la ligne à contrôler mais NE PEUT PAS être peuplé du contrôle à la ligne". La liaison de données entre "MyColumn" et "CheckState" ne l'atteint pas. Pour un comportement correct, vous devez connecter l'événement Format/Parse et modifier la valeur de passage. - Si tel est le cas, comme l'a souvent écrit @Max, il vaut mieux utiliser une solution réutilisable. – TcKs

1

La façon easist Je sais, est dérive de la classe CheckBox, ajoutez la propriété « DataValue » qui peut manipuler des valeurs DBNull et lier la données « DataValue » propriété:

public class DataCheckBox : CheckBox { 
    public virtual object DataValue { 
     get { return this.Checked; } 
     set { 
      if (value == null || value is DBNull) { 
       this.CheckState = CheckState.Indeterminate; 
      } 
      else { 
       this.Checked = (bool)value; 
      } 
     } 
    } 
} 
+0

Eh bien, c'est un astucieux ... – Mac

+0

Intelligent mais pas vraiment nécessaire puisque CheckBox supporte la liaison de données aux colonnes NULL (DBNull) comme je l'ai démontré. –

Questions connexes