web-dev-qa-db-ja.com

SelectedItemプロパティへのUWPコンボボックスのバインド

最終的にいくつかの設定に使用できるように、バインディングでコンボボックスを機能させようとしています。監視可能なコレクションから入力するアイテムを取得し、「SelectedItem」をプロパティにバインドできますSelectedItem="{x:Bind SelectedComboBoxOption}"

しかし、選択を変更すると、テキストボックスには反映されず、このプロパティにもバインドされます。背後のコードでは、起動時にプロパティを1回設定しますが、コンボボックスのアイテムを変更するときは設定しません。私は何かを逃しているに違いありませんが、私には何が明確ではありません。何か案は?

これは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;
 }
}
10
RonaldA

@Mike Easonと@kubakistaが言ったように、Modeを明示的に設定する必要があります。ただし、これで問題が完全に修正されるわけではありません。

コードでは、SelectedComboBoxOptionは文字列ですが、SelectedItemComboBoxItemオブジェクトです。 StringSelectedItemにバインドしても、ComboBoxの選択されたアイテムは変更されません。したがって、SelectedComboBoxOptionを使用してComboBoxの選択した項目を取得および設定する場合は、SelectedComboBoxOptionComboBoxItemに変更し、{x:Bind}で変換を使用して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}にキャストするときに issue があります。回避策として、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>
12
Jay Zuo

デフォルトでは、x:BindOneTimeに設定されます。モードをOneWayに設定するだけでこれを修正できます。

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

別の解決策(もう少しMVVMのようなもの)は、コードビハインドでComboBoxItem型のオブジェクトを作成し、そのオブジェクトにバインドしてから、コードビハインドでオブジェクトを操作して目的の文字列を取得することです。これにより、コンバータを作成する必要がなくなります。

C#
public ComboBoxItem ComboBoxItemSelected {get; set;}

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