views:

798

answers:

2

hello,

i've got two comboboxes with the same content. the user should not be allowed to choose the same item twice. therefore the comboboxes' contents (= selectedindex?) should never be equal.

my first attempt was to comapare the selectedindex with a datatrigger to show/hide a button:

<DataTrigger Binding="{Binding ElementName=comboBox1, Path=SelectedIndex}" Value="{Binding ElementName=comboBox2, Path=SelectedIndex}">
     <Setter Property="Visibility" Value="Hidden" />
</DataTrigger>

it seems that it is not possible to use Value={Binding}. is there any other way (if possible without using a converter)? thanks in advance!

A: 

Option 1

You could use ValidationRules -- it can also be done in XAML, and will work for a one-off situation. It would be extremely localized and not something I would recommend since the rule would not be reusable. Maybe somebody else can come up with a generic rule to encompass different inputs. Try this out.

<ComboBox>
    <ComboBox.SelectedValue>
        <Binding Path="Whatever" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:ComparisonValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </ComboBox.SelectedValue>
</ComboBox>

And maybe the ComparisonRule looks like this, and it would have to be in the code-behind for that rule to see the controls in the visual tree.

public class ComparisonValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            if (this.firstComboBox.SelectedIndex == this.secondComboBox.SelectedIndex)
                return new ValidationResult(false, "These two comboboxes must supply different values.");
            else return new ValidationResult(true, null);
        }
    }

OR you could definitely do it with a trigger if you wanted to set some interesting things outside of an error template.

Option 2

Use a trigger & converter.. It's really not too difficult. Here's how I would do it.

    <Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource EqualsConverter}">
                        <Binding ElementName="cbOne" Path="SelectedIndex"/>
                        <Binding ElementName="cbTwo" Path="SelectedIndex"/>
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="Yellow"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>

and the converter in code-behind

public class EqualsConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType,
                          object parameter, CultureInfo culture)
    {
        if (values[0] is int && values[1] is int && values[0] == values[1])
            return true;
        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes,

                                object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
Erode
A: 

If the ComboBoxes share the same itemsource, set a flag on the underlying data object when an item is selected via the first ComboBox.

In the datatemplate for the data object displayed in the second combobox write a datatrigger that binds to that property and does something appropriate.

Ensure your binding is TwoWay for the first ComboBox.

Kevin Mills