简体   繁体   中英

SelectedItem binding on ComboBox not showing selected value

I'm trying to build a settings page to allow the user to choice which action to execute on item swipe, like the Outlook app.

To do this I created an enum containing the available actions, and I'm binding it to a ComboBox .

Everything works, the user can choose the action and his choice is saved correctly. The problem is that the ComboBox doesn't show the selected item when I navigate to the page, it shows it only after selection.

This means that if user changes selection then the ComboBox is updated, but the selected item is shown as blank upon navigation.

Here's my code:

(XAML)

<ComboBox x:Uid="LeftActionComboBox"
          Grid.Row="0"                          
          HorizontalAlignment="Stretch"                          
          SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay, Converter={StaticResource StringToSwipeActionTypesConverter}}"
          ItemsSource="{Binding LeftSwipeActionType, Converter={StaticResource EnumToStringListConverter}}"/>

(VM Property)

public SwipeActionTypes LeftSwipeActionType
{
    get { return _settings.LeftSwipeActionTypeProperty; }
    set
    {
        _settings.LeftSwipeActionTypeProperty = value;
        // RaisePropertyChanged causes a StackOverflow, but not using it is not the problem since the ComboBox is empty only before set
    }
}

(Converter StringToSwipeActionTypesConverter , localization-ready)

// Returns localized string value for the Enum
public object Convert(object value, Type targetType, object parameter, string language)
{
    var enumValue = (SwipeActionTypes) value;
    switch (enumValue)
    {
        case SwipeActionTypes.Copy:
            return App.ResourceLoader.GetString("CopySwipeActionName");
        case SwipeActionTypes.Delete:
            return App.ResourceLoader.GetString("DeleteSwipeActionName");
        default:
            throw new ArgumentOutOfRangeException();
    }
}

// Parses the localized string into the enum value
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
    var stringValue = (string) value;
    if (stringValue.Equals(App.ResourceLoader.GetString("CopySwipeActionName")))
    {
        return SwipeActionTypes.Copy;
    }
    if (stringValue.Equals(App.ResourceLoader.GetString("DeleteSwipeActionName")))
    {
        return SwipeActionTypes.Delete;
    }
    return null;
}

(Converter EnumToStringListConverter )

public object Convert(object value, Type targetType, object parameter, string language)
{
    var valueType = value.GetType();
    return Enum.GetNames(valueType).ToList();
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
    return value;
}

Any idea on why this is failing?

First of all, here is whats wrong with your approach: You are binding your ItemsSource to the same property as the SelectedItem , even tough you are using a converter this can cause an infinite update circle - and you don't want that.

Generating the same static list of elements over and over again seems a bit wasteful. Instead of passing an instance of a type, lets just pass the type itself to the converter:

EnumToMembersConverter.cs

public class EnumToMembersConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        return Enum.GetValues((Type)value).ToList();
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return DependencyProperty.UnsetValue;
    }
}

XAML

ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}"

This will give you all Values of SwipeActionTypes , therefore you can bind it directly, without converting back again.

SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"

There is nothing wrong with using a ComboBox for types other than string, so lets make this your base for further steps:

<ComboBox x:Uid="LeftActionComboBox"
      Grid.Row="0"                          
      HorizontalAlignment="Stretch"                          
      SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"
      ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}"/>

The reason you wrote all those converts is probably because the ComboBox showed strange values instead of readable strings. No worries, we already have your converter, you just need to invert it (Convert SwipeActionTypes to String ) and apply it to a TextBox:

<ComboBox x:Uid="LeftActionComboBox"
      Grid.Row="0"                          
      HorizontalAlignment="Stretch"                          
      SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"
      ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=., Converter = {StaticResource SwipeActionTypesStringConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Note, I didn't run this code so you might need to adjust the used namespaces accordingly

The reason you are getting a StackOverflow exception is because every time you change LeftSwipeActionType property you are changing the ItemsSource of the ComboBox which changes the SelectedItem which fires INotifyPropertyChanged which changes the ItemsSource and so on and so on.

Once you stop using the same property for ItemsSource and SelectedItem then the correct initial selection will be set.

Rather than use a converter to create your ItemsSource you should just create is in your ViewModel

public MyViewModel(type enumType)
{
    SourceForItems = Enum.GetValues(enumType);
}

public IEnumerable SourceForItems { get; private set; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM