-1

There's this combo box in a WPF application that is populated from an enum. How would one disable some of its items? Disabling has to be dynamic, based on another property in the ViewModel.

<ComboBox ItemsSource="{utility:EnumMarkupExtension {x:Type types:SomeEnum}}"
          SelectedItem="{Binding Path=MySelection, Converter={StaticResource SomeEnumToString}}" />

EnumMarkupExtension is defined thus:

public sealed class EnumMarkupExtension : MarkupExtension
{
    public Type Type { get; set; }
    public EnumMarkupExtension(Type type) => this.Type = type;

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        string[] names = Enum.GetNames(Type);
        string[] values = new string[names.Length];

        for (int i = 0; i < names.Length; i++) 
            values[i] = Resources.ResourceManager.GetString(names[i]);
        return values;
    }
}

(SomeEnumToString is an IValueConverter which probably is not relevant to this)

Is there some obvious method of doing this that I'm missing?

I've seen solutions like this https://www.codeproject.com/Tips/687055/Disabling-ComboboxItem-in-ComboBox-Control-using-C but can't figure out how to pass a property to IValueConverter since ConverterParameter is not bindable.

Indivara
  • 735
  • 1
  • 7
  • 19
  • 3
    Disabling an item would mean to bind the IsEnabled property of an individual ComboBoxItem to a property of a view model item. This would be done in an ItemContainerStyle. And it would require to bind the ItemsSource to a collection of view model items with a source property for that Binding. – Clemens May 24 '20 at 08:43
  • I agree with @clemens. If you share, based on what type of property in viewmodel u want disable to items in combobox, would be able to suggest something. – neelesh bodgal May 24 '20 at 10:21
  • @Clemens Thanks, I'll try this tomorrow. I guess I'll have to rewrite the part that populates the combo. The property used to disable some items is just a bool value. – Indivara May 24 '20 at 14:38
  • 1
    It should be a boolean property with change notification, since it "*has to be dynamic*". – Clemens May 24 '20 at 14:44
  • I had forgotten that. You're right, I'm using Prism, I'll do a `SetProperty` on it. – Indivara May 24 '20 at 14:47
  • @Clemens I got this working using your method, thanks so much! Could you put this in an answer so that I may accept it? – Indivara May 25 '20 at 00:15

3 Answers3

0

I know you have solved the issue with the help of @clemens. Still posting an answer for others who might same question.

Assuming VMDataSource is datasource in Viewmodel and with each item in VMDataSource contains a boolean flag to indicate whether to enable/ disable the item. Following code snippet would work as you queried in the post.

    <ComboBox ItemsSource="{Binding VMDataSource}">
        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Setter Property="IsEnabled" Value="{Binding Path="VMDisableItem"/>
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox> 

Assuming VMDataSource is datasource in Viewmodel and viewmodel contains a Non-boolean property to indicate whether to enable/ disable the item instead of datasource itself containing a bool property to enable/diasble the item(Incase of enums). In this case a multibinding and a converter that would take the item in VMDataSource and a non-boolean property to enable/disable an item as follows

    <ComboBox DataContext="{StaticResource viewmodelInstance}"
        ItemsSource="{Binding VMDataSource}">
        <ComboBox.Resources>
            <local:Disabler x:Key="disabler"/>
        </ComboBox.Resources>
        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Setter Property="IsEnabled">
                    <Setter.Value>
                        <MultiBinding Converter="{StaticResource disabler}">
                            <!--Here you can bind the proper u want to use in -->
                            <!--converter to enable/ disable comboboxitem-->
                            <!--Currently it is bound property of viewmodelInstance that as non-boolean property-->                               
                            <Binding 
                                RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=ComboBox}"
                                Path="DataContext.VMDisableItem"/>


                            <!--Bind to the current comboboxitem which needs to enabled/disabled-->
                            <Binding />
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox>

Assuming typeof(VMDisableItem) and typeof(VMDataSource) are both string. When both are equal, disable the item otherwise enable.

class Disabler : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return !Equals(values[0], values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
neelesh bodgal
  • 632
  • 5
  • 14
-1

You can use a multiBinding where one of the values is instead of the ConverterParameter. See this answer

Efraim Newman
  • 927
  • 6
  • 21
-2

Edit the comboboxitem itemtemplate, in the item template bind IsEnabled with the value of the viewmodel (it should be an index) and converter paraemeter the value of the item itself.

DrkDeveloper
  • 939
  • 7
  • 17