Derrick Moeller
Derrick Moeller

Reputation: 4950

Retrieving enum from ListBox SelectedItems property

I have an Enum defined, my intention is to display the four options(None, Left, Center, and Right) to a user in a ListBox. This ListBox will allow for multiple selections. When the save command is clicked I must pass the selections to the ViewModel where I will aggregate the selections and pass this to a WCF service.

Enum:

[DataContract]
[Flags]
public enum Locations
{
    None = 0,
    [EnumMember]
    Left = 1,
    [EnumMember]
    Center = 2,
    [EnumMember]
    Right = 4,
    [EnumMember]
    LeftCenter = Left | Center,
    [EnumMember]
    LeftRight = Left | Right,
    [EnumMember]
    CenterRight = Center | Right,
    [EnumMember]
    All = Left | Center | Right
}

XAML:

<Button Command="{Binding SaveCommand}"
        CommandParameter="{Binding SelectedItems, ElementName=lbLocations}" />
<ListBox x:Name="lbLocations" SelectionMode="Multiple">
    <ListBoxItem Content="{x:Static m:Subsections.None}" />
    <ListBoxItem Content="{x:Static m:Subsections.Left}" />
    <ListBoxItem Content="{x:Static m:Subsections.Center}" />
    <ListBoxItem Content="{x:Static m:Subsections.Right}" />
</ListBox>

ViewModel:

public ICommand SaveCommand
{
    get
    {
        if (_saveCommand == null)
            _saveCommand = new RelayCommand<IList>(x => Save(x));

         return _saveCommand;
    }
}

private void Save(IList locations)
{
    try
    {
        // ToList() produces InvalidCastException.
        var collection = locations.Cast<Locations>().ToList();

        // Do WCF stuff, display success, etc.
    }
    catch (Exception ex)
    {
        _dialogService.Show(ex.Message, "Error");
    }
}

I have successfully passed the selections back to my ViewModel as an IList, but I'm having difficulty casting it back to my enum. Is there a better approach I have overlooked, can this work? It seems like I'm nearly there.

Upvotes: 2

Views: 140

Answers (2)

Glen Thomas
Glen Thomas

Reputation: 10744

There is a better way to achieve this:

Create a class to hold data for each item in the ListBox

class EnumSelection
{
    public bool IsSelected { get; set; }

    public Subsections Value { get; set; }

    public EnumSelection(Subsections value)
    {
        Value = value;
    }
}

Bind the ItemsSource property of the ListBox to the available enums

private IEnumerable<EnumSelection> enums;
public IEnumerable<EnumSelection> Enums
{
    get
    {
        if (this.enums == null)
        {
            this.enums = Enum.GetValues(typeof(Subsections)).Cast<Subsections>().Select(s => new EnumSelection(s));
        }

        return this.enums;
    }
}

public IEnumerable<EnumSelection> SelectedItems
{
    get
    {
        return Enums.Where(e => e.IsSelected);
    }
}

Use a DataTemplate to bind to the new class

<ListBox ItemsSource="{Binding Enums}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding IsSelected}"/>
                <TextBlock Text="{Binding Value}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Save method:

ICommand _saveCommand;
public ICommand SaveCommand
{
    get
    {
        return this._saveCommand
               ?? (this._saveCommand = new RelayCommand<IEnumerable<EnumSelection>>(x => this.Save(x)));
    }
}

private void Save(IEnumerable<EnumSelection> enums)
{
}

Upvotes: 0

almulo
almulo

Reputation: 4978

Try iterating through the casted list and aggregating the value into a single variable, like this:

private void Save(IList locations)
{
    try
    {
        Locations location = Locations.None;

        foreach (Locations value in locations.Cast<Locations>())
        {
            location |= value;
        }

        // Do WCF stuff, display success, etc.
    }
    catch (Exception ex)
    {
        _dialogService.Show(ex.Message, "Error");
    }
}

Upvotes: 1

Related Questions