Sandy
Sandy

Reputation: 71

WPF ComboBox - case insensitive data-binding

If I'm databinding a WPF combo box, is there a way to make the binding case insensitive?

For example if the combo box is bound to a property whose value is HELLO, get it to select combo box item with value of Hello?

Upvotes: 7

Views: 2270

Answers (3)

MrPlow254
MrPlow254

Reputation: 73

Here is a c# version of @bkstill selected value ignore case converter.

/// <summary>
/// Converts selected value to case ignore.
/// </summary>
/// <seealso cref="System.Windows.Data.IMultiValueConverter" />
public class SelectedValueIgnoreCaseConverter : IMultiValueConverter {
    /// <summary>
    /// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target.
    /// </summary>
    /// <param name="values">The array of values that the source bindings in the <see cref="T:System.Windows.Data.MultiBinding" /> produces. The value <see cref="F:System.Windows.DependencyProperty.UnsetValue" /> indicates that the source binding has no value to provide for conversion.</param>
    /// <param name="targetType">The type of the binding target property.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value.If the method returns <see langword="null" />, the valid <see langword="null" /> value is used.A return value of <see cref="T:System.Windows.DependencyProperty" />.<see cref="F:System.Windows.DependencyProperty.UnsetValue" /> indicates that the converter did not produce a value, and that the binding will use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue" /> if it is available, or else will use the default value.A return value of <see cref="T:System.Windows.Data.Binding" />.<see cref="F:System.Windows.Data.Binding.DoNothing" /> indicates that the binding does not transfer the value or use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue" /> or the default value.
    /// </returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
        if (typeof(string) != values[0].GetType()) {
            return null;
        }

        string selectedValue = values[0].ToString();

        ObservableCollection<string> options = (ObservableCollection<string>) values[1];

        if (selectedValue.IsNullOrEmpty()) {
            return null;
        }

        return options.FirstOrDefault(option => option.Equals(selectedValue, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// Converts a binding target value to the source binding values.
    /// </summary>
    /// <param name="value">The value that the binding target produces.</param>
    /// <param name="targetTypes">The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// An array of values that have been converted from the target value back to the source values.
    /// </returns>
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
        object[] result = new object[1];
        result[0] = value;
        return result;
    }
}

Upvotes: 0

bkstill
bkstill

Reputation: 677

I accomplished this by implementing an IMultiValueConverter.

The converter is applied to the ItemsSource binding on the ComboBox and sets two bindings. The first for the value that is to be selected. The second is bound to the ItemsSource property of the ComboBox which is a list of possible values.

<ComboBox ItemsSource="{Binding Path=DataContext.EntityTypeOptions, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
    <ComboBox.SelectedValue>
        <MultiBinding Converter="{StaticResource SelectedValueIgnoreCaseConverter}">
            <Binding Path="UpdatedValue" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged" />
            <Binding Path="ItemsSource" Mode="OneWay" RelativeSource="{RelativeSource Mode=Self}" />
        </MultiBinding>
    </ComboBox.SelectedValue>
</ComboBox>

For the converter, the Convert() method finds the selected value in the ItemsSource ignoring case and then returns a matching value from the ItemsSource.

The ConvertBack() method simply puts the selected value back in the first element of the object array.

Imports System.Globalization
Imports System.Windows.Data
Imports System.Collections.ObjectModel

Public Class SelectedValueIgnoreCaseConverter
    Implements IMultiValueConverter

    Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert
        Dim selectedValue As String = TryCast(values(0), String)
        Dim options As ObservableCollection(Of String) = TryCast(values(1), ObservableCollection(Of String))

        If selectedValue Is Nothing Or options Is Nothing Then
            Return Nothing
        End If

        options.Contains(selectedValue, StringComparer.OrdinalIgnoreCase)
        Dim returnValue As String = Utilities.Conversions.ParseNullToString((From o In options Where String.Equals(selectedValue, o, StringComparison.OrdinalIgnoreCase)).FirstOrDefault)

        Return returnValue
    End Function

    Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
        Dim result(2) As Object
        result(0) = value
        Return result
    End Function
End Class

Upvotes: 1

James Hurst
James Hurst

Reputation: 147

Create a new property on your view-model that provides the property-value converted into a string in the form you want. Bind your ComboBox (or other WPF widget) to that property.

For example:

public string NameOfValue
{
    get
    {
        return this.OtherProperty.ToCapitalizedString();
    }
}

In this way you have control over exactly how that property-value gets formatted to display it. However, now you have to add a change-notification to that other property, so that when you change the value of OtherProperty, the data-binding knows to update the display of the new property.

public string OtherProperty
{
    get { .. }
    set
    {
        Notify();
        Notify("NameOfValue");
    }
}

Upvotes: 0

Related Questions