简体   繁体   English

ComboBox上的SelectedItem绑定未显示所选值

[英]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. 我正在尝试构建一个设置页面,以允许用户选择要在项目滑动(例如Outlook应用)上执行的操作。

To do this I created an enum containing the available actions, and I'm binding it to a ComboBox . 为此,我创建了一个包含可用操作的enum ,并将其绑定到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. 问题在于,当我导航到页面时, ComboBox不会显示所选的项目,它仅在选择后显示。

This means that if user changes selection then the ComboBox is updated, but the selected item is shown as blank upon navigation. 这意味着,如果用户更改选择,则ComboBox会更新,但是所选项目在导航时显示为空白。

Here's my code: 这是我的代码:

(XAML) (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) (VM属性)

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) (转换器StringToSwipeActionTypesConverter ,已准备好本地化)

// 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 ) (转换器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. 首先,这是您的方法有什么问题:您正在将ItemsSource绑定到与SelectedItem相同的属性,即使使用转换器很难,这可能会导致无限的更新周期-并且您不希望这样做。

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 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 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. 这将为您提供SwipeActionTypes所有 ,因此您可以直接绑定它,而无需再次转换。

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并没有错,因此,请使其成为进一步操作的基础:

<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. 您写所有这些转换的原因可能是因为ComboBox显示了奇怪的值而不是可读的字符串。 No worries, we already have your converter, you just need to invert it (Convert SwipeActionTypes to String ) and apply it to a TextBox: 不用担心,我们已经有了您的转换器,您只需要对其进行转换 (将SwipeActionTypes转换为String )并将其应用于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. 出现StackOverflow异常的原因是,每次更改LeftSwipeActionType属性时,您都在更改ComboBox的ItemsSource,它更改了SelectedItem,从而触发了INotifyPropertyChanged,从而更改了ItemsSource,依此类推。

Once you stop using the same property for ItemsSource and SelectedItem then the correct initial selection will be set. 一旦停止对ItemsSource和SelectedItem使用相同的属性,则将设置正确的初始选择。

Rather than use a converter to create your ItemsSource you should just create is in your ViewModel 而不是使用转换器来创建ItemsSource,而应该在ViewModel中创建

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

public IEnumerable SourceForItems { get; private set; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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