2

I have below combo box in mvvm-wpf application. I need to implement "Text search" in this..(along with multibinding). Can anybody help me please.

<StackPanel Orientation="Horizontal">
    <TextBlock Text="Bid Service Cat ID"
                Margin="2"></TextBlock>
    <ComboBox Width="200"
                Height="20"
                SelectedValuePath="BidServiceCategoryId"
                SelectedValue="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}},
                    Path=DataContext.SelectedBidServiceCategoryId.Value}"
                ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}},
                    Path=DataContext.BenefitCategoryList}"
                Margin="12,0">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock DataContext="{Binding}">
                            <TextBlock.Text>
                                <MultiBinding StringFormat="{}{0}: {1}">
                                <Binding Path="BidServiceCategoryId" />
                                <Binding Path="BidServiceCategoryName" />
                            </MultiBinding>
                            </TextBlock.Text></TextBlock>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
</StackPanel>
decyclone
  • 30,394
  • 6
  • 63
  • 80
Relativity
  • 6,690
  • 22
  • 78
  • 128

2 Answers2

6

Unfortunately, TextSearch.Text doesn't work in a DataTemplate. Otherwise you could have done something like this

<ComboBox ...>
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="TextSearch.Text">
                <Setter.Value>
                    <MultiBinding StringFormat="{}{0}: {1}">
                        <Binding Path="BidServiceCategoryId"/>
                        <Binding Path="BidServiceCategoryName"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

However this won't work, so I see two solutions to your problem.

First way
You set IsTextSearchEnabled to True for the ComboBox, override ToString in your source class and change the MultiBinding in the TextBlock to a Binding

Xaml

<ComboBox ...
          IsTextSearchEnabled="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>

Source class

public class TheNameOfYourSourceClass
{
    public override string ToString()
    {
        return String.Format("{0}: {1}", BidServiceCategoryId, BidServiceCategoryName);
    }
    //...
}

Second Way
If you don't want to override ToString I think you'll have to introduce a new Property in your source class where you combine BidServiceCategoryId and BidServiceCategoryName for the TextSearch.TextPath. In this example I call it BidServiceCategory. For this to work, you'll have to call OnPropertyChanged("BidServiceCategory"); when BidServiceCategoryId or BidServiceCategoryName changes as well. If they are normal CLR properties, you can do this in set, and if they are dependency properties you'll have to use the property changed callback

Xaml

<ComboBox ...
          TextSearch.TextPath="BidServiceCategory"
          IsTextSearchEnabled="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock DataContext="{Binding}">
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{0}: {1}">
                        <Binding Path="BidServiceCategoryId" />
                        <Binding Path="BidServiceCategoryName" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DataTemplate>
    </ComboBox.ItemTemplate>

Source class

public class TheNameOfYourSourceClass
{
    public string BidServiceCategory
    {
        get
        {
            return String.Format("{0}: {1}", BidServiceCategoryId, BidServiceCategoryName);
        }
    }

    private string m_bidServiceCategoryId;
    public string BidServiceCategoryId
    {
        get
        {
            return m_bidServiceCategoryId;
        }
        set
        {
            m_bidServiceCategoryId = value;
            OnPropertyChanged("BidServiceCategoryId");
            OnPropertyChanged("BidServiceCategory");
        }
    }

    private string m_bidServiceCategoryName;
    public string BidServiceCategoryName
    {
        get
        {
            return m_bidServiceCategoryName;
        }
        set
        {
            m_bidServiceCategoryName = value;
            OnPropertyChanged("BidServiceCategoryName");
            OnPropertyChanged("BidServiceCategory");
        }
    }
}
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
  • The first method ..is not working for me...it's not displaying. Only object is geting displayed..not value in that – Relativity Jan 20 '11 at 22:17
  • @Anish Mohan: Have you checked if the ToString method is getting hit in the debugger? If so, what value does it return? Do you think it would help if I uploaded my sample project? – Fredrik Hedblad Jan 20 '11 at 22:20
  • Hi, ToString is not getting called . – Relativity Jan 20 '11 at 22:27
  • The DataContext is BenefitCategoryList, which seems to be a Collection of something like BenefitCategory instances, is this correct? In that case, an instance of BenefitCategory should be the DataContext for each ComboBoxItem, and the ToString should be called to present each item. I'm not sure what's missing here. Can you post the source for the source class perhaps? – Fredrik Hedblad Jan 20 '11 at 22:31
  • YEs ...but BenefitCategory is a dto...and i have added ToString method over there. But it never called. I think..we have to have these two properties in viewmodel...and ToSting shud be in view model – Relativity Jan 20 '11 at 22:33
  • When you bind directly to the DataContext, which is a class in this case, the framework will call the ToString method when presenting it. If you don't override ToString it will return the default value which is the fully qualified name, meaning namespace.classname. Hopefully that was clear, did it answer your question? :) – Fredrik Hedblad Jan 20 '11 at 22:56
  • Yes, very much..Thank youuuuuuuuuuuuuuu – Relativity Jan 21 '11 at 00:05
  • Does Solution 2 work when search anywhere in your string. For instance, does the search text need to start with BidServiceCategoryID since that is the first field displayed in BidServiceCategory? Basically can you do a wildcard or substring search with this solution? – Darlene Nov 07 '13 at 18:24
3

I don't know if your text search has to search ALL the text, but if you want to search from the category ID, you can just set the TextSearch.TextPath property to BidServiceCategoryId. That should also be helpful for anyone who wants to use multibinding and finds that the text search no longer works... It does work if you explicitly set the TextPath property.