views:

620

answers:

2

Hi board,

in another topic, I've stumbled over this very elegant solution by Darin Dimitrov to filter the DataSource of one ComboBox with the selection of another ComboBox: how to filter combobox in combobox using c#

combo2.DataSource = ((IEnumerable<string>)c.DataSource)
.Where(x => x == (string)combo1.SelectedValue);

I would like to do a similar thing, but intead of filtering by a second combobox, I would like to filter by the text of a TextBox. (Basically, instead of choosing from a second ComboBox, the user simply enters his filter in to a TextBox). However, it turned out to be not as straight forward as I had hoped it would be. I tried stuff as the following, but failed miserably:

     cbWohndresse.DataSource = ((IEnumerable<DataSet>)ds)
            .Where(x => x.Tables["Adresse"].Select("AdrLabel LIKE '%TEST%'"));
        cbWohndresse.DisplayMember = "Adresse.AdrLabel";
        cbWohndresse.ValueMember = "Adresse.adress_id";

ds is the DataSet which I would like to use as filtered DataSource. "Adresse" is one DataTable in this DataSet. It contains a DataColumn "AdrLabel". Now I would like to display only those "AdrLabel", which contain the string from the user input. (Currently, %TEST% replaces the textbox.text.)

The above code fails because the lambda expression does not return Bool. But I am sure, there are also other problems (which type should I use for IEnumerable? Now it's DataSet, but Darin used String. But how could I convert a DataSet to a string?

Yes, I am as much newbyish as it gets, my experience is "void", and publicly so. So please forgive me my rather stupid questions.

Your help is greatly appreciated, because I can't solve this on my own (tried hard already).

Thank you very much!

Pesche

P.S. I am only using Linq to achieve an uncomplicated filter for the ComboBox (avoiding a View). The rest is not based on Linq, but on oldstyle Ado.NET (ds is filled by an SqlDataAdapter), if that's of any importance.

+2  A: 

LINQ does not seem, to me, like an obvious solution here. Your data is already loaded into a DataSet structure, so you should be able to do something like this:

var adresse = ds.Tables["Adresse"];
adresse.DefaultView.RowFilter = "AdrLabel LIKE '%TEST%'";

cbWohndresse.DataSource = adresse;
cbWohndresse.DisplayMember = "AdrLabel";
cbWohndresse.ValueMember = "adress_id"
cbWohndresse.DataBind();

To address the actual problems in your current code:

  1. If ds is of type DataSet, casting it to IEnumerable<DataSet> will fail.
  2. DataTable.Select returns an array of rows, not a boolean.
  3. Ignoring #1 and #2, your Where() call would return zero, one or more DataSet instances which each have a table named "Adresse" with at least one row matching the filter. Hence, you end up binding your presentational control to a set of DataSet instances, which is not what you need.
Jørn Schou-Rode
Thank you very much for your super-fast replay! This looks like a straight forward approach I wasn't aware of, before! Also the analysis of the actual problem is very interesting to me - since I am a beginner and eager to learn :)
Pesche Helfer
A: 

If you want to use LINQ, then you'll need to add a reference System.Data.DataSetExtensions. You can then query your DataSet in a "linqish" manner.

The blog post Querying DataSets – Introduction to LINQ to DataSet by Erick Thompson, a PM at Microsoft is a good introduction to LINQ to DataSets

Here's a very crude example:

XAML

<StackPanel>

    <TextBox x:Name="MyFilter" />

    <ComboBox x:Name="MyComboBox" 
              ItemsSource="{Binding}"
              DisplayMemberPath="AdrLabel" />

    <Button Click="OnFilterClick">Filter</Button>

</StackPanel>

Code Behind

public partial class FilteredDataSet : Window
{
    public FilteredDataSet()
    {
        InitializeComponent();

        CreateDataContext();
        MyComboBox.DataContext = MyDataSet.Tables[0];
    }

    private DataSet MyDataSet { get; set; }
    private void CreateDataContext()
    {
        var ds = new DataSet();
        var dt = new DataTable( "Adresse" );
        ds.Tables.Add( dt );

        var dc = new DataColumn( "AdrLabel" );
        dt.Columns.Add( dc );

        DataRow dr = dt.NewRow();
        dr[0] = "one";
        dt.Rows.Add( dr );

        dr = dt.NewRow();
        dr[0] = "honed";
        dt.Rows.Add( dr );

        dr = dt.NewRow();
        dr[0] = "obiwone";
        dt.Rows.Add( dr );

        dr = dt.NewRow();
        dr[0] = "won";
        dt.Rows.Add( dr );

        MyDataSet = ds;

    }
    private void OnFilterClick( object sender, RoutedEventArgs e )
    {
        string filter = MyFilter.Text;

        var context = MyDataSet.Tables[0].AsEnumerable()
            .Where( dr => dr.Field<string>( "AdrLabel" ).Contains( filter ) )
            .Select( dr => dr.Field<string>( "AdrLabel" ) );

        MyComboBox.DisplayMemberPath = string.Empty;

        MyComboBox.DataContext = context;
    }
}
Metro Smurf
My many thanks also go to you! This really seems to be a great place with very helpful, friendly people. Now I have different approaches to my problem, giving me the best possible insight. Thank you very much!Unfortunately, I don't have enough reputation to vote, yet.
Pesche Helfer
Come back, visit, contribute :) Be sure to "accept" answers to your question(s). And Welcome!
Metro Smurf
Ehm, can I accept two answers? The green checkmark will only stick to one answer ...
Pesche Helfer
Only one answer can be accepted. You won't hurt anyone's feeling by not selected them as an answer. Just be sure to selected the answer that worked for you. :)
Metro Smurf
Well, that's a pity, since both answers are great and working. I just give you a virtual thumbs up, then :)
Pesche Helfer