2013-03-21 12 views
8

La mia domanda è fondamentalmente this one. Ho pensato che sarebbe stato utile fornire ulteriori informazioni e codice che rendessero più semplice riprodurre il problema.Come selezionare l'oggetto SelectedItem di RibbonComboBox

Lavorare con Microsoft.Windows.Controls.Ribbon.RibbonComboBox dallo RibbonControlsLibrary sembra di camminare in una grande palude piena di bug, non qualcosa che si fa se si sa come aggirarla.

Anywho. Il problema più grande che ho riscontrato era l'associazione del mio SelectedItem.

Quanto segue è quello che ho iniziato con (dopo aver scoperto RibbonGallery?). Avere ItemsSource e SelectedItem su sottoelementi del ComboBox e nemmeno sullo stesso livello mi ha già dato l'heebie-jeebies, ma sembra essere corretto.

Nell'app di esempio, sto impostando SelectedItem nel costruttore di ViewModel. Tuttavia, quando si esegue l'app, non viene visualizzato SelectedItem. Anche il progettista VS mostra correttamente "seconda opzione"!

Esecuzione app: Running App VS progettista: Visual Studio Designer

Quando il debug il setter SelectedItem, si noterà più passaggi. Dopo averlo impostato per la prima volta su "seconda opzione" nel ctor (1, vedere il registro di debug sotto), verrà ripristinato su null (2) (per codice esterno, conto nel controllo stesso). Quando si apre il menu a discesa nell'interfaccia utente, verrà nuovamente impostato su null (3), quindi quando si seleziona un valore, due volte su questo valore (4,5). Ho selezionato "seconda opzione", quindi ho ripetuto la procedura con "prima opzione" (6-9). Ciò ha prodotto il seguente registro (ignorando le mille e un'eccezioni vincolanti dal controllo del nastro ...):

enter image description here

Il grosso problema, ovviamente, è (2), che è il ripristino mia selezione iniziale. Sembra che quando il controllo viene mostrato la prima volta, viene resettato. Una soluzione molto brutta sarebbe quella di impostare il valore con un timer. Impostarlo nell'evento Loaded del controllo utente funziona per me in questa app di esempio, ma nella mia app realistica più pesante, non è così. Ad ogni modo, tutto ciò sembra sbagliato. Qualcuno conosce una soluzione migliore?

Xaml:

<UserControl x:Class="WpfApplication1.RibbonComboBoxDemo" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:r="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon" 
      xmlns:local="clr-namespace:WpfApplication1" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 

    <UserControl.DataContext> 
     <local:ViewModel /> 
    </UserControl.DataContext> 

    <Grid> 
     <r:Ribbon > 
      <r:RibbonTab Header="First Tab"> 
       <r:RibbonGroup Header="Group"> 
        <r:RibbonComboBox > 
         <r:RibbonGallery SelectedItem="{Binding SelectedItem, Mode=TwoWay}"> 
          <r:RibbonGalleryCategory ItemsSource="{Binding Controls}" DisplayMemberPath="Caption" /> 
         </r:RibbonGallery> 
        </r:RibbonComboBox> 
       </r:RibbonGroup> 
      </r:RibbonTab> 
      <r:RibbonTab Header="Second Tab" /> 
     </r:Ribbon> 
    </Grid> 
</UserControl> 

ViewModel:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Diagnostics; 

namespace WpfApplication1 
{ 
    public class ViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void OnPropertyChanged(string propertyName) 
     { 
      if (this.PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 

     public ObservableCollection<ControlBaseModel> Controls { get; private set; } 


     private ControlBaseModel _selectedItem; 
     public ControlBaseModel SelectedItem { get { return _selectedItem; } set { LogSelectedItemChange(value); _selectedItem = value; OnPropertyChanged("SelectedItem"); } } 

     public ViewModel() 
     { 
      this.Controls = new ObservableCollection<ControlBaseModel>(); 

      this.Controls.Add(new ControlBaseModel() { Caption = "first option" }); 
      this.Controls.Add(new ControlBaseModel() { Caption = "second option" }); 

      this.SelectedItem = this.Controls[1]; // set to second option 
     } 

     int i = 0; 
     private void LogSelectedItemChange(ControlBaseModel value) 
     { 
      i++; 
      string setObject = "null"; 
      if (value != null) 
      { 
       setObject = value.Caption; 
      } 
      Debug.WriteLine(string.Format("{0}: SelectedItem.set(): {1}", i, setObject)); 
     } 

    } 

    public class ControlBaseModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void OnPropertyChanged(string propertyName) 
     { 
      if (this.PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 

     private string _name; 
     public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } 

     private string _caption; 
     public string Caption { get { return _caption; } set { _caption = value; OnPropertyChanged("Caption"); } } 
    } 
} 

risposta

5

mentre la vista/UserControl evento caricato è in corso prima che il ComboBox SelectedItem viene reimpostato su null nella mia richiesta, il ComboBox caricata evento è infatti licenziato due volte, la seconda volta "tardi" abbastanza. Così la mia soluzione attuale, che io fosso volentieri per uno migliore, è questo:

<r:RibbonComboBox> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="Loaded"> 
      <i:InvokeCommandAction Command="{Binding LoadedCommand}" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
    <r:RibbonGallery SelectedItem="{Binding SelectedItem, Mode=TwoWay}"> 
     <r:RibbonGalleryCategory ItemsSource="{Binding Controls}" DisplayMemberPath="Caption"/> 
    </r:RibbonGallery> 
</r:RibbonComboBox> 

ViewModel:

private ControlBaseModel _lastNonNullSelectedItem; 

public ObservableCollection<ControlBaseModel> Controls { get; private set; } 

private ControlBaseModel _selectedItem; 
public ControlBaseModel SelectedItem 
{ 
    get { return _selectedItem; } 
    set 
    { 
     if (value != null) { _lastNonNullSelectedItem = value; } 
     _selectedItem = value; 
     OnPropertyChanged("SelectedItem"); 
    } 
} 
public ICommand LoadedCommand { get; private set; } 


public ViewModel() 
{ 
    this.Controls = new ObservableCollection<ControlBaseModel>(); 
    this.LoadedCommand = new ActionCommand(OnLoaded); // ActionCommand: simple implementation of ICommand 

    this.Controls.Add(new ControlBaseModel() { Caption = "first option" }); 
    this.Controls.Add(new ControlBaseModel() { Caption = "second option" }); 

    this.SelectedItem = this.Controls[1]; // set to second option 
} 

private void OnLoaded() 
{ 
    this.SelectedItem = _lastNonNullSelectedItem; 
} 
+0

Tu mi ha salvato una quantità enorme di tempo ...Grazie mille !!! –

2

Ho finito solo usando la casella combinata standard.

<ComboBox SelectedItem="{Binding Item}" ItemsSource="{Binding Items}"/> 

Se si desidera che lo stesso stile (molto simile) come RibbonComboBox, utilizzare

<ComboBox IsEditable="True" IsReadOnly="True" SelectedItem="{Binding Item}" ItemsSource="{Binding Items}"/> 
Problemi correlati