绑定到SelectedItem属性的UWP组合框

本文关键字:UWP 组合 属性 SelectedItem 绑定 | 更新日期: 2023-09-27 18:22:44

我正在尝试获得一个用于绑定的组合框,以便最终可以将其用于某些设置。我可以从可观察的集合中获取要填充的项,并将"SelectedItem"绑定到属性SelectedItem="{x:Bind SelectedComboBoxOption}"

但当我更改选择时,这不会反映在同样绑定到此属性的文本框中。在后面的代码中,它在启动时设置一次属性,但在更改组合框中的项目时不设置。我一定错过了什么,但我不清楚是什么。有什么想法吗?

这是XAML:

<Page
x:Class="ComboBoxTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ComboBoxTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <ComboBox 
            Name="ComboBox" 
            ItemsSource="{x:Bind ComboBoxOptions}" 
            SelectedItem="{x:Bind SelectedComboBoxOption, Mode=TwoWay}" 
            SelectedValuePath="ComboBoxOption" 
            DisplayMemberPath="ComboBoxHumanReadableOption"  
            Header="ComboBox" >
        </ComboBox>
        <TextBlock Name="BoundTextblock" Text="{x:Bind SelectedComboBoxOption}"/>
    </StackPanel>
</Grid>

这是背后的代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace ComboBoxTest
{
 public sealed partial class MainPage : Page, INotifyPropertyChanged
 {
    private ObservableCollection<ComboBoxItem> ComboBoxOptions;
    public MainPage()
    {
        this.InitializeComponent();
        ComboBoxOptions = new ObservableCollection<ComboBoxItem>();
        ComboBoxOptionsManager.GetComboBoxList(ComboBoxOptions);
    }
    public class ComboBoxItem
    {
        public string ComboBoxOption { get; set; }
        public string ComboBoxHumanReadableOption { get; set; }
    }
    public class ComboBoxOptionsManager
    {
        public static void GetComboBoxList(ObservableCollection<ComboBoxItem> ComboBoxItems)
        {
            var allItems = getComboBoxItems();
            ComboBoxItems.Clear();
            allItems.ForEach(p => ComboBoxItems.Add(p));
        }
        private static List<ComboBoxItem> getComboBoxItems()
        {
            var items = new List<ComboBoxItem>();
            items.Add(new ComboBoxItem() { ComboBoxOption = "Option1", ComboBoxHumanReadableOption = "Option 1" });
            items.Add(new ComboBoxItem() { ComboBoxOption = "Option2", ComboBoxHumanReadableOption = "Option 2" });
            items.Add(new ComboBoxItem() { ComboBoxOption = "Option3", ComboBoxHumanReadableOption = "Option 3" });
            return items;
        }
    }

    string _SelectedComboBoxOption = "Option1";
    public string SelectedComboBoxOption
    {
        get
        {
            return _SelectedComboBoxOption;
        }
        set
        {
            if (_SelectedComboBoxOption != value)
            {
                _SelectedComboBoxOption = value;
                RaisePropertyChanged("SelectedComboBoxOption");
            }
        }
    }
    void RaisePropertyChanged(string prop)
    {
        if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
    }
    public event PropertyChangedEventHandler PropertyChanged;
 }
}

绑定到SelectedItem属性的UWP组合框

正如@Mike Eason和@kubakista所说,您需要显式设置Mode。但这并不能完全解决你的问题。

在代码中,SelectedComboBoxOption是一个字符串,但SelectedItem是一个ComboBoxItem对象。将String绑定到SelectedItem不会更改ComboBox的选定项。因此,如果要使用SelectedComboBoxOption来获取和设置ComboBox的选定项,则需要将SelectedComboBoxOption更改为ComboBoxItem,并在{x:Bind}中使用Convert在ObjectComboBoxItem之间进行转换。

转换可能喜欢:

public class ComboBoxItemConvert : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return value as MainPage.ComboBoxItem;
    }
}

XAML可能喜欢:

<Page ...>
    <Page.Resources>
        <local:ComboBoxItemConvert x:Key="ComboBoxItemConvert" />
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <ComboBox Name="ComboBox"
                      DisplayMemberPath="ComboBoxHumanReadableOption"
                      Header="ComboBox"
                      ItemsSource="{x:Bind ComboBoxOptions}"
                      SelectedItem="{x:Bind SelectedComboBoxOption, Mode=TwoWay, Converter={StaticResource ComboBoxItemConvert}}"
                      SelectedValuePath="ComboBoxOption" />
            <TextBlock Name="BoundTextblock" Text="{x:Bind SelectedComboBoxOption.ComboBoxHumanReadableOption, Mode=OneWay}" />
        </StackPanel>
    </Grid>
</Page>

在后面的代码中:

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    private ObservableCollection<ComboBoxItem> ComboBoxOptions;
    public MainPage()
    {
        this.InitializeComponent();
        ComboBoxOptions = new ObservableCollection<ComboBoxItem>();
        ComboBoxOptionsManager.GetComboBoxList(ComboBoxOptions);
        SelectedComboBoxOption = ComboBoxOptions[0];
    }
    ...
    private ComboBoxItem _SelectedComboBoxOption;
    public ComboBoxItem SelectedComboBoxOption
    {
        get
        {
            return _SelectedComboBoxOption;
        }
        set
        {
            if (_SelectedComboBoxOption != value)
            {
                _SelectedComboBoxOption = value;
                RaisePropertyChanged("SelectedComboBoxOption");
            }
        }
    }
    ...
}

如果您只想在TextBlock中显示所选项目,有一种简单的方法。我们可以将TextBlockText属性绑定到ComboBoxSelectedItem。请注意,SelectedItem的类型是System.Object{x:Bind}是强类型的,并且将解析路径中每个步骤的类型。如果返回的类型没有成员,它将在编译时失败。因此,我们需要指定一个强制转换来告诉绑定对象的真实类型。但是在{x:Bind}中强制转换嵌套类时出现了一个问题。我们可以将ComboBoxItemMainPage中删除,作为一种变通方法。

namespace ComboBoxTest
{
    public class ComboBoxItem
    {
        public string ComboBoxOption { get; set; }
        public string ComboBoxHumanReadableOption { get; set; }
    }
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        ...
    }
}

在XAML中:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <ComboBox Name="ComboBox"
                  DisplayMemberPath="ComboBoxHumanReadableOption"
                  Header="ComboBox"
                  ItemsSource="{x:Bind ComboBoxOptions}"
                  SelectedValuePath="ComboBoxOption" />
        <TextBlock Name="BoundTextblock" Text="{x:Bind ComboBox.SelectedItem.(local:ComboBoxItem.ComboBoxHumanReadableOption), Mode=OneWay}" />
    </StackPanel>
</Grid>

默认情况下,x:Bind设置为OneTime。您可以通过简单地将模式设置为OneWay来解决此问题。

Text="{x:Bind SelectedComboBoxOption, Mode=OneWay}"

另一个解决方案(更像MVVM)是在代码后台创建一个ComboBoxItem类型的对象,绑定到该对象,然后让代码后台操作该对象以获得所需的字符串。这将消除你必须创建一个转换器:

C#
public ComboBoxItem ComboBoxItemSelected {get; set;}
XAML
SelectedItem = "{Binding ComboBoxItemSelected, Mode=TwoWay}"