HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

WPF Load boolean values in combobox

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
booleanwpfloadvaluescombobox

Problem

I have a Combobox and I want to edit a boolean value.



My ViewModel:

/// 
    /// Contains the ItemsSource for Enums
    /// 
    public List EnumItemsSource
    {
        get { return _enumItemsSource; }
        set
        {
            _enumItemsSource = value;
            OnPropertyChanged();
        }
    }

public class EnumItemObject
{
   public int Id {get;set;}
   public string Name {get;set;}
}


And I prepare the data for the Combobox ItemsSource that:

/// 
    /// Sets the value to the properties for the BitTemplate view. (similar with EnumTemplate)
    /// 
    /// a boolean property
    private void PrepareDataForBitTemplate(PropertyInfo propertyInfo)
    {
        TargetValue = (int)propertyInfo.GetValue(_firstSelectedItem);
        EnumItemsSource = new List();
        EnumItemsSource.Add(new EnumItemObject() { Id = 0, Name = "Nein" });
        EnumItemsSource.Add(new EnumItemObject() { Id = 1, Name = "Ja" });
    }


Is it the approach correct? Is there any easier solution?

UPDATE:
Extract from my ViewModel code (you remember EnumItemsSource is ItemsSource for Combobox and TargetValue the Combobox selected item):

```
private void LookUpViewData()
{
var propertyInfo = _firstSelectedItem.GetType().GetProperty(TargetFieldDescription.fdBigViewColumnName);
if ((propertyInfo != null) && (propertyInfo.GetValue(_firstSelectedItem) != null))
{
if ((int) FieldDataType.ENum == TargetFieldDescription.fdDataType)
PrepareDataForEnumTemplate(propertyInfo);
if ((int) FieldDataType.Bit == TargetFieldDescription.fdDataType)
PrepareDataForBitTemplate(propertyInfo); // like EnumTemplate
else if ((int) FieldDataType.Time == TargetFieldDescription.fdDataType)
PrepareDataForTimeTemplate(propertyInfo);
else
PrepareDataForDefaultTemplate(propertyInfo);
}
else
TargetValue = String.E

Solution

It's not clear where this PrepareDataForBitTemplate(PropertyInfo) method is located. Is it code-behind? Whatever it is, if the goal is to bind a ComboBox with some enum values, I would much rather keep it standard - meaning the DataContext of the ComboBox is the ViewModel of the containing Window or UserControl:

public IEnumerable ViewModelEnumValues
{
    get { return Enum.GetValues(typeof(SomeEnumType)).Cast(); }
}

private SomeEnumType _selectedEnumValue;
public SomeEnumType SelectedEnumValue
{
    get { return _selectedEnumValue; }
    set { _selectedEnumValue = value; NotifyPropertyChanged(() => SelectedEnumValue); }
}


Before I move on to the corresponding XAML markup, a few observations:

  • The ViewModel implementation derives from some ViewModelBase abstract class which implements INotifyPropertyChanged and allows its derivatives to specify a property name in a strongly-typed way. I see your setter calls some OnPropertyChanged() method, but not how that method is able to notify the View that a specific property was changed.



  • The name Enum refers to a specific language construct. Calling something "Enum" when that something is not an enum is rather confusing.



  • I don't see why you're not using an actual enum when the values you're trying to load are basically "Yes" and "No".



  • EnumItemObject is an awful name, for several reasons:



  • It's not an object, it's a class - an object is an instance of a class.



  • It's not an enum item, it's essentially a ViewModel that exposes two properties - an int and a string.



  • It's not immediately apparent how this class relates to any type of enum.



Now, given that your ViewModel exposes the above SelectedEnumValue and ViewModelEnumValues properties (both bad/stub names), with a ValueConverter the XAML for the ComboBox would be as simple as this:


    
        
             
                
                    
                    
                
            
        
    


And the converters would look like this:

using resx = Project.Properties.Resources;    

public class EnumValueToStringConverter : ConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        SomeEnumType result;
        return Enum.TryParse(value.ToString(), out result)
                   ? resx.ResourceManager.GetString(promoType + "Caption")
                   : string.Empty;
    }
}

public class EnumValueToIconConverter : ConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var result = string.Empty;
        var typedValue = value As SomeEnumType;
        if (typedValue != null)
        {
            switch(typedValue)
            {
                case SomeEnumType.EnumValue1:
                    result = "images/image-for-value1.png";
                    break;
                case SomeEnumType.EnumValue2:
                    result = "images/image-for-value2.png";
                    break;
            }
        }

        return new BitmapImage(new Uri("/project.namespace;component/" + result, UriKind.Relative));
    }
}


Of course this is overkill if all you want is the enum names in your dropdown list - but I tend to define a DataTemplate for just about everything (and I think I have a tendency to abuse converters, too).

If all you need is to display an enum value directly in the UI, then this will suffice:

public IEnumerable ViewModelEnumNames
{
    get { return Enum.GetNames(typeof(SomeEnumType)).ToList(); }
}

private string _selectedEnumName;
public string SelectedEnumName
{
    get { return _selectedEnumName; }
    set { _selectedEnumName = value; NotifyPropertyChanged(() => SelectedEnumName); }
}


Code Snippets

public IEnumerable<SomeEnumType> ViewModelEnumValues
{
    get { return Enum.GetValues(typeof(SomeEnumType)).Cast<SomeEnumType>(); }
}

private SomeEnumType _selectedEnumValue;
public SomeEnumType SelectedEnumValue
{
    get { return _selectedEnumValue; }
    set { _selectedEnumValue = value; NotifyPropertyChanged(() => SelectedEnumValue); }
}
<ComboBox ItemSource="{Binding ViewModelEnumValues}"
          SelectedItem="{Binding SelectedEnumValue, Mode=TwoWay}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Border Style="{StaticResource ListItemBorder}"> <!-- just some border -->
                <StackPanel>
                    <Image Source="{Binding Value, Converter={StaticResource EnumValueIconConverter}}" />
                    <Label Content="{Binding Value, Converter={StaticResource EnumValueNameConverter}}" />
                </StackPanel>
            </Border>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
using resx = Project.Properties.Resources;    

public class EnumValueToStringConverter : ConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        SomeEnumType result;
        return Enum.TryParse(value.ToString(), out result)
                   ? resx.ResourceManager.GetString(promoType + "Caption")
                   : string.Empty;
    }
}

public class EnumValueToIconConverter : ConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var result = string.Empty;
        var typedValue = value As SomeEnumType;
        if (typedValue != null)
        {
            switch(typedValue)
            {
                case SomeEnumType.EnumValue1:
                    result = "images/image-for-value1.png";
                    break;
                case SomeEnumType.EnumValue2:
                    result = "images/image-for-value2.png";
                    break;
            }
        }

        return new BitmapImage(new Uri("/project.namespace;component/" + result, UriKind.Relative));
    }
}
public IEnumerable<string> ViewModelEnumNames
{
    get { return Enum.GetNames(typeof(SomeEnumType)).ToList(); }
}

private string _selectedEnumName;
public string SelectedEnumName
{
    get { return _selectedEnumName; }
    set { _selectedEnumName = value; NotifyPropertyChanged(() => SelectedEnumName); }
}
<ComboBox ItemSource="{Binding ViewModelEnumNames}"
          SelectedItem="{Binding SelectedEnumName, Mode=TwoWay}">

Context

StackExchange Code Review Q#36255, answer score: 3

Revisions (0)

No revisions yet.