Reputation: 1233
I have a problem building a simple crud form in WP7. I have spent a lot of time to display an Enum into a listpicker an now I see InvalidCastException when trying to bind to the (IsolatedStorage) object.
public class Bath {
public string Colour { get; set; }
public WaterType WaterType { get; set; }
}
public enum WaterType {
Hot,
Cold
}
The enum is bound to a ListPicker, but as there is not enum.GetValues() in WP7 this is not a simple task.
I have a simple type class...
public class TypeList
{
public string Name { get; set; }
}
And in my viewmodel, I have ObservableCollection and mock the values from the enum...
private ObservableCollection<TypeList> _WaterTypeList;
public ObservableCollection<TypeList> WaterTypeList
{
get { return _WaterTypeList; }
set
{
_WaterTypeList= value;
NotifyPropertyChanged("WaterTypeList");
}
}
public void LoadCollectionsFromDatabase()
{
ObservableCollection<TypeList> wTypeList = new ObservableCollection<WaterTypeList>();
wTypeList.Add(new TypeList{ Name = WaterType.Hot.ToString() });
wTypeList.Add(new TypeList{ Name = WaterType.Income.ToString() });
WaterTypeList = new ObservableCollection<TypeList>(wTypeList);
}
Finally, my xaml contains the listbox...
<toolkit:ListPicker
x:Name="BathTypeListPicker"
ItemsSource="{Binding WaterTypeList}"
DisplayMemberPath="Name">
</toolkit:ListPicker>
Im not sure if the above is best practise and indeed if the above is part of the problem but the above does give me a populated ListPicker.
Finally, when the form is submitted the cast causes a InvalidCastException.
private void SaveAppBarButton_Click(object sender, EventArgs e)
{
var xyz = WaterTypeList.SelectedItem; // type AppName.Model.typeList
Bath b = new Bath
{
Colour = ColourTextBox.Text ?? "Black",
WaterType = (WaterType)WaterTypeListPicker.SelectedItem
};
App.ViewModel.EditBath(b);
NavigationService.Navigate(new Uri("/Somewhere.xaml", UriKind.Relative));
}
}
Has anyone faced a simlar problem and can offer advice. I see that my opions are to concentrate on casting something meaningful from the ListPicker or should I rethink the way that the ListPicker is populated?
Upvotes: 2
Views: 456
Reputation: 66882
The WaterTypeListPicker.SelectedItem
is an object of type TypeList
so it can't be cast to an object of type WaterType
.
In order to convert back to a WaterType, you could replace your cast:
WaterType = (WaterType)WaterTypeListPicker.SelectedItem
with:
WaterType = (WaterType)Enum.Parse(
typeof(WaterType),
((TypeList)WaterTypeListPicker.SelectedItem).Name,
false)
Upvotes: 1
Reputation: 10865
As far as I can see, WaterTypeList is an ObservableCollection that is a Type of and an observable collection doesn't have a SelectedItem property.
Your Bath class has a WaterType that accepts WaterType property and you are trying to cast a WaterTypeListPicker.SelectedItem to it.. so I'm assuming your WatertypeListPicker is your ListBox?
If it is, then you are doing it wrong because your ListBox's itemssource is bound to a class and you are trying to add a to your WaterType Property.
What I would do is say,
Bath b = new Bath
{
Colour = ColourTextBox.Text ?? "Black",
WaterType = WaterTypeListPicker.SelectedItem
};
Either change my property of Bath's WaterType to a TypeList so the above code would work. But I won't recommend doing another class to wrap the enum just to show it to the listbox.
What I would do is create an EnumHelper
public static class EnumExtensions
{
public static T[] GetEnumValues<T>()
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("Type '" + type.Name + "' is not an enum");
return (
from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select (T)field.GetValue(null)
).ToArray();
}
public static string[] GetEnumStrings<T>()
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("Type '" + type.Name + "' is not an enum");
return (
from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select field.Name
).ToArray();
}
}
And Bind it to a Collection
My ViewModel
public IEnumerable<string> Priority
{
get { return EnumExtensions.GetEnumValues<Priority>().Select(priority => priority.ToString()); }
public string SelectedPriority
{
get { return Model.Priority; }
set { Model.Priority = value; }
}
Like that.
My XAML.
<telerikInput:RadListPicker SelectedItem="{Binding SelectedPriority, Mode=TwoWay}" ItemsSource="{Binding Priority}" Grid.Column="1" Grid.Row="4"/>
Upvotes: 3