2

I have an ObjectDataProvider for getting a list of enum members:

<ObjectDataProvider x:Key="GetEnumContents" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
    <ObjectDataProvider.MethodParameters>
         <x:Type TypeName="Data:Status"/>
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

which I then use with:

<ComboBox SelectedItem="{Binding Status, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Source={StaticResource GetEnumContents}}" />

In the same window, I'd then like to have a combo box for a different enum. How do I pass the enum type from the ComboBox declaration?

I've seen solutions to similar problems something like:

Path="MethodParameters[0]"

but here I don't want to bind the parameter to anything, I just want to hard-code it in the ComboBox declaration.

Any ideas?

Jasper Kent
  • 3,546
  • 15
  • 21
  • I'm pretty sure that `ObjectDataProvider` doesn't support that kind functionality. You need a provider per type. The ODP just acts as a thin wrapper around the method call. – Bradley Uffner Oct 29 '18 at 17:07
  • I think you may be able to rig up an `IValueConverter` to get the kind of functionality you want though. Give me a few minutes to try it, and if it works out, I'll post an answer for you. – Bradley Uffner Oct 29 '18 at 17:10

1 Answers1

2

ObjectDataProvider doesn't support that kind of functionality, but you can "fake" it with the clever abuse usage of a Binding and an IValueConverter.

First, the IValueConverter:

class EnumConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Enum.GetValues((Type)parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Here is how you use it:

<Window
    x:Class="EnumTest.MainWindow"
    [...snip...]
    xmlns:local="clr-namespace:EnumTest"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <local:EnumConverter x:Key="EnumConverter" />
    </Window.Resources>
    <StackPanel>
        <ComboBox ItemsSource="{Binding Converter={StaticResource EnumConverter}, ConverterParameter={x:Type local:MyEnum1}}" />
        <ComboBox ItemsSource="{Binding Converter={StaticResource EnumConverter}, ConverterParameter={x:Type local:MyEnum2}}" />
    </StackPanel>
</Window>

Some Test Enums:

enum MyEnum1
{
    Red,
    Green,
    Blue,
}

enum MyEnum2
{
    Cat,
    Dog,
    Fish,
    Bird,
}

This produces the following output: enter image description here enter image description here

This takes advantage of the fact that you can pass an extra parameter to an IValueConverter, which I use to pass the Type of the enumeration to the converter. The converter just calls Enum.GetNames on that argument, and returns the result. The actual Binding will actually be bound to whatever the DataContext of the ComboBox happens to be. The EnumConverter just happily ignores it and operates on the parameter instead.


UPDATE

It works even better by binding directly to the type, skipping the ConverterParameter entirely, like so:

<ComboBox ItemsSource="{Binding Source={x:Type local:MyEnum1}, Converter={StaticResource EnumConverter}}" />

With adjustments to the converter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    return Enum.GetValues((Type)value);
}

Same result with less typing, and easier to understand, code.

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
  • That works, but there's a slight different from using the ObjectDataProvider. With the ObjectDataProvider, the ComboBox displays the the current value of the data that the ComboBox is bound to, but with Converter, it just shows blank. – Jasper Kent Oct 31 '18 at 11:02
  • That's just because I left off the `SelectedItem` binding from your code to keep my example simple. That's not related to the `ObjectDataProvider` at all. If you use that binding from your original code, it *should* work. If you try that, and it doesn't work, let me know and I'll try to figure out what's going on. – Bradley Uffner Oct 31 '18 at 11:35
  • I've still got the SelectedItem in there, just as in my original code. – Jasper Kent Oct 31 '18 at 11:41
  • Ok, I'll try to figure out why that isn't working. There isn't any reason off the top of my head why it *wouldn't* work. – Bradley Uffner Oct 31 '18 at 11:52
  • 1
    Ahh, it just hit me what the problem is. My converter is returning a list of *strings* instead of a list of the enumeration *values*. Since the binding property is the actual enum value, it fails to find a match. It's an easy fix. Just change the return statement in the converter to `return Enum.GetValues((Type)value);`. I'm updating the answer now. – Bradley Uffner Oct 31 '18 at 13:46
  • That works. I could have worked that out. I'm so lazy. :( – Jasper Kent Oct 31 '18 at 18:05