I have been going crazy with binding a combobox to an enum typed property of a class, where the enum itself is declared in that same class.
I am trying to follow the answer provided here (wpf combobox binding to enum what i did wrong?) Specifically I am using the suggested MarkupExtension code and the matching xaml code.
My working code is:
Defining the Enum in a separate file.
namespace EnumTest
{
public enum TestEnum {one, two, three, four };
}
Class that uses the Enum (Note that the propertyChanged code has been removed to simplify things):
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
Program file that uses the class:
namespace EnumTest
{
public partial class Window1 : Window
{
Test _oTest = new Test();
public Window1()
{
InitializeComponent();
cmbBox.DataContext = _oTest;
}
}
}
Extension method for displaying the Enum
namespace EnumTest
{
[MarkupExtensionReturnType(typeof(object[]))]
public class EnumValuesExtension : MarkupExtension
{
public EnumValuesExtension()
{
}
public EnumValuesExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.EnumType == null)
throw new ArgumentException("The enum type is not set");
return Enum.GetValues(this.EnumType);
}
}
}
And the xaml code that is used to display the data:
<Window x:Class="EnumTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:EnumTest"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox Name="cmbBox"
Height="20"
Width="80"
ItemsSource="{Binding Source={w:EnumValues EnumType=w:TestEnum}}"
SelectedItem="{Binding Path=MyVar}"
/>
</Grid>
</Window>
The above is all good and dandy, but I want to define the Enum within the Test class and ditch the Enum from being defined at the global scope. Like so:
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
// Declare Enum **INSIDE** the class
public enum TestEnum {one, two, three, four };
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
The SO question I referred to alludes to the matching xaml syntax as being:
<ComboBox Name="cmbBox"
...
ItemsSource="{Binding Source={w:EnumValues EnumType=w:Test+TestEnum}}"
...
/>
But this (sort of) does not work for me. When I do a clean build I get a "Build succeeded" message on the VS 2008 status bar, but I also get an error being reported in the xaml
Type 'Test+TestEnum' was not found.
But the code runs as expected!
However this means that the xaml designer will not load. So I am sort of screwed in doing any more wpf work until I can clear the xaml error.
I am now wondering if this is a VS 2008 SP1 issue, and not a problem on my part.
Edit
- Made my problem statement more explicit.
- Tried Joel's 1st solution, but I ended up with the code running and 2 xaml errors
- Tried Joel's 2nd solution and that worked straight out of the box - so I am going with that one!
Notes
The SO question that I got the MarkupExtension code from uses this style of syntax for the xaml:
<ComboBox ItemsSource="{w:EnumValues w:TestEnum}"/>
When I use that I get a compilation error saying that no EnumValues constructor takes 1 parameter. I did some googling and this seems to be an error in VS. I Am using VS 2008 SP1. I did see some comments that alluded to it being in the VS 2010 beta. Anyway, that is why I use the xaml syntax of
<ComboBox ItemsSource="{w:EnumValues EnumType=w:TestEnum}"/>
As this syntax works!
See Question&Answers more detail:
os