webentwicklung-frage-antwort-db.com.de

UWP Combobox-Bindung an die SelectedItem-Eigenschaft

Ich versuche, eine Combobox mit der Bindung zu verknüpfen, damit ich sie für einige Einstellungen verwenden kann. Ich kann die Elemente aus einer beobachtbaren Sammlung auffüllen und 'SelectedItem' an eine Eigenschaft binden. SelectedItem="{x:Bind SelectedComboBoxOption}"

Wenn ich jedoch die Auswahl ändere, wird dies nicht in der Textbox angezeigt, die auch an diese Eigenschaft gebunden ist. Im Code dahinter wird die Eigenschaft einmal beim Start festgelegt, nicht jedoch beim Ändern von Elementen in der Combobox. Mir muss etwas fehlen, aber mir ist nicht klar was. Irgendwelche Ideen?

Dies ist die 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>

Und das ist der Code dahinter:

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;
 }
}
9
RonaldA

Wie @Mike Eason und @kubakista sagten, müssen Sie Mode explizit festlegen. Damit wird Ihr Problem jedoch nicht vollständig behoben.

In Ihrem Code ist Ihr SelectedComboBoxOption ein String, aber das SelectedItem ist ein ComboBoxItem - Objekt. Durch das Binden einer String an SelectedItem wird das ausgewählte Element von ComboBox nicht geändert. Wenn Sie also SelectedComboBoxOption verwenden möchten, um das ausgewählte Element von ComboBox abzurufen und festzulegen, müssen Sie SelectedComboBoxOption in ComboBoxItem ändern und einen Umrechner in {x:Bind}, Um zwischen Object und ComboBoxItem zu konvertieren.

Der Konverter mag vielleicht:

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;
    }
}

Die XAML kann mögen:

<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>

Im Code-Behind:

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");
            }
        }
    }
    ...
}

Wenn Sie nur das ausgewählte Element in TextBlock anzeigen möchten, gibt es einen einfachen Weg. Wir können die Eigenschaft TextBlock von Text an die Eigenschaft ComboBox von SelectedItem binden. Bitte beachten Sie, dass der Typ von SelectedItemSystem.Object Und {x:Bind} Stark typisiert ist und den Typ jedes Schritts in einem Pfad auflöst. Wenn der zurückgegebene Typ kein Mitglied hat, schlägt die Kompilierung fehl. Wir müssen also eine Besetzung angeben, um den realen Typ des Objekts zu bestimmen. Es gibt jedoch ein Problem , während die verschachtelte Klasse in {x:Bind} Umgewandelt wird. Wir können ComboBoxItem aus MainPage als Workaround setzen.

namespace ComboBoxTest
{
    public class ComboBoxItem
    {
        public string ComboBoxOption { get; set; }
        public string ComboBoxHumanReadableOption { get; set; }
    }

    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        ...
    }
}

Und in der 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>
12
Jay Zuo

Standardmäßig ist x:Bind auf OneTime eingestellt. Sie können dies beheben, indem Sie einfach den Modus auf OneWay setzen.

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

Eine andere (etwas MVVM-ähnliche) Lösung besteht darin, ein Objekt vom Typ ComboBoxItem in Ihrem Code-Behind zu erstellen, an dieses Objekt zu binden und dann das Objekt von Ihrem Code-Behind manipulieren zu lassen, um die gewünschte Zeichenfolge zu erhalten. Dadurch müssten Sie keinen Konverter erstellen:

C#
public ComboBoxItem ComboBoxItemSelected {get; set;}

XAML
SelectedItem = "{Binding ComboBoxItemSelected, Mode=TwoWay}"
0
Jeffrey McNeal