views:

376

answers:

1

Hi board

I am trying to write a method, that takes a ComboBox, a DataTable and a TextBox as arguments. The purpose of it is to filter the members displayed in the ComboBox according to the TextBox.Text. The DataTable contains the entire list of possible entries that will then be filtered. For filtering, I create a DataView of the DataTable, add a RowFilter and then bind this View to the ComboBox as DataSource.

To prevent the user from typing into the ComboBox, I choose the DropDownStyle DropDownList. That’s working fine so far, except that the user should also be able to choose nothing / empty line. In fact, this should be the default member to be displayed (to prevent choosing a wrong member by accident, if the user clicks through the dialog too fast).

I tried to solve this problem by adding a new Row to the view. While this works for some cases, the main issue here is that any DataTable can be passed to the method. If the DataTable contains columns that cannot be null and don’t contain a default value, I suppose I will raise an error by adding an empty row.

A possibility would be to create a view that contains only the column that is defined as DisplayMember, and the one that is defined as ValueMember. Alas, this can’t be done with a view in C#. I would like to avoid creating a true copy of the DataTable at all cost, since who knows how big it will get with time.

Do you have any suggestions how to get around this problem?

Instead of a view, could I create an object containing two members and assign the DisplayMember and the ValueMember to these members? Would the members be passed as reference (what I hope) or would true copied be created (in which case it would not be a solution)?

Thank you very much for your help!

Best regards

public static void ComboFilter(ComboBox cb, DataTable dtSource, TextBox filterTextBox)
{
 cb.DropDownStyle = ComboBoxStyle.DropDownList;
 string displayMember = cb.DisplayMember;
 DataView filterView = new DataView(dtSource);
 filterView.AddNew();
 filterView.RowFilter = displayMember + " LIKE '%" + filterTextBox.Text + "%'";
 cb.DataSource = filterView;
}
A: 

Ok, by chance, I stumbled over a working solution: Any changes to a DataView - such as adding a new row - are supposed to be completed using .EndEdit. If you don't do that, you'll be confronted with side effects, such as the added row not being sorted properly. BUT: by not adding .EndEdit, you'll also get an advantage: C# won't check, if any of the columns in the underlying DataTable (dtSource) does not allow null!

So, as a solution, I added .EndEdit to a try-Block. If the DataTable allows null for every column, it will work and the empty line will appear on top of the combobox. If it doesn't allow null, EndEdit won't be executed, the empty line will still be added, at the bottom of the ComboBox, however.

Please note that if you have set autoincrement in dtSource, the empty line will also return a SelectedValue (most likely -1). This needs to be considered when using this method!

Cheers!

public static void ComboFilter(ComboBox cb, DataTable dtSource, TextBox filterTextBox)
{
    cb.DropDownStyle = ComboBoxStyle.DropDownList;
    string displayMember = cb.DisplayMember;
    DataView filterView = new DataView(dtSource);
    DataRowView newRow = filterView.AddNew();
    newRow[displayMember] = "";
    try { newRow.EndEdit(); }   // fails, if a column in dtSource does not allow null
    catch (Exception) { }       // works, but the empty line will appear at the end
    filterView.RowFilter = displayMember + " LIKE '%" + filterTextBox.Text + "%'";
    filterView.Sort = displayMember;
    cb.DataSource = filterView;
}
Pesche Helfer