2015-11-20 37 views
8

Sto cercando di far funzionare una combobox con il binding in modo che possa eventualmente utilizzarlo per alcune impostazioni. Posso ottenere gli elementi da popolare da una raccolta osservabile e associare 'SelectedItem' a una proprietà SelectedItem="{x:Bind SelectedComboBoxOption}"UWP Combobox vincolante alla proprietà SelectedItem

Ma quando cambio la selezione questo non si riflette nella casella di testo anche associata a questa proprietà. Nel codice sottostante imposta la proprietà una volta all'avvio ma non quando si cambiano gli elementi nella casella combinata. Devo mancare qualcosa ma non mi è chiaro cosa. Qualche idea?

Questa è la 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> 

e questo è il codice dietro:

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

risposta

10

Come @ Mike Eason e @kubakista Detto questo, è necessario impostare in modo esplicito Mode. Ma questo non risolverà completamente il tuo problema.

Nel codice, il numero SelectedComboBoxOption è una stringa, ma lo SelectedItem è un oggetto ComboBoxItem. Il collegamento di un numero da String a SelectedItem non cambierà l'elemento selezionato di ComboBox. Quindi, se si desidera utilizzare SelectedComboBoxOption per ottenere e impostare ComboBox 's voce selezionata, è necessario modificare SelectedComboBoxOption a ComboBoxItem e utilizzare un convertito in {x:Bind} per la conversione tra Object e ComboBoxItem.

Converti può piacere:

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

Il XAML può piacere:

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

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

Se vuoi solo mostrare l'elemento selezionato in TextBlock, c'è un modo semplice. Siamo in grado di legare lo Text SelectedItem. E si noti che il tipo SelectedItem è System.Object e {x:Bind} è fortemente digitato e risolverà il tipo di ogni passaggio in un percorso. Se il tipo restituito non ha il membro, fallirà al momento della compilazione. Quindi abbiamo bisogno di specificare un cast per dire di legare il vero tipo dell'oggetto. Ma c'è un issue mentre esegui il cast della classe nidificata in {x:Bind}. Possiamo mettere ComboBoxItem su MainPage come soluzione alternativa.

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

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

E nel 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> 
+0

Funziona perfettamente! Grazie mille anche per l'ottima spiegazione. Come novizio non è sempre facile capire perché le cose siano fatte in un certo modo. – RonaldA

+0

@Jay, ho avuto il problema opposto. Dopo l'inizializzazione è vuoto e puoi selezionare normalmente. Puoi dare un'occhiata a questo problema, per favore? Grazie! http://stackoverflow.com/questions/39090923/why-this-uwp-combobox-can-be-blank-after-initialization-but-works-fine-for-selec – litaoshen

0

Per impostazione predefinita, x:Bind è impostato su OneTime. È possibile rimediare semplicemente impostando la modalità su OneWay.

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

Purtroppo questo non sembra fare la differenza.Inoltre, dal momento che voglio caricare una preferenza e farla riflettere nella casella combinata, non dovrei usare: 'Mode = TwoWay'? – RonaldA

+0

@RonaldA Per SelectedItem mantieni 'Mode = TwoWay' ma per la tua proprietà' Text' in 'TextBlock' devi usare' Mode = OneWay'. –

Problemi correlati