2013-03-21 11 views
8

Moje pytanie jest w zasadzie this one. Pomyślałem, że pomoże to dostarczyć więcej informacji i kodu, który ułatwia odtworzenie problemu.Jak wybrać databind SelectedItem RibbonComboBox

Praca z Microsoft.Windows.Controls.Ribbon.RibbonComboBox z RibbonControlsLibrary to jak spacerowanie po wielkim bagnie pełnym błędów, a nie coś, co robisz, jeśli znasz sposób na jego obejście.

Anywho. Największym problemem, jaki napotkałem, było powiązanie mojego SelectedItem.

Oto, od czego zacząłem (po tym, jak dowiedziałem się o RibbonGallery?). Posiadanie ItemsSource i SelectedItem w podelementach ComboBox, a nawet na tym samym poziomie, nie dało mi już heebiego, ale wydaje się to poprawne.

W przykładowej aplikacji ustawiam SelectedItem w konstruktorze ViewModel. Jednak podczas uruchamiania aplikacji nie jest wyświetlany żaden SelectedItem. Nawet projektant VS poprawnie pokazuje "drugą opcję"!

Uruchamianie aplikacji: Running App VS projektant: Visual Studio Designer

Gdy debugowanie setter SelectedItem, zauważysz wiele podań. Po ustawieniu go po raz pierwszy na "drugą opcję" w ctor (1, patrz dziennik debugowania poniżej), zostanie on zresetowany do wartości null (2) (przez zewnętrzny kod, uważam, że w samej kontroli). Podczas otwierania listy rozwijanej w interfejsie użytkownika zostanie ona ponownie ustawiona na zero (3), a następnie przy wybieraniu wartości dwa razy do tej wartości (4,5). Wybrałem "drugą opcję", a następnie powtórzyłem procedurę z "pierwszą opcją" (6-9). Ten wyprodukowany następujący log (pomijając na tysiąc i jeden wiążących wyjątki od kontroli wstążką ...):

enter image description here

Dużym problemem jest oczywiście (2), który jest zresetowanie mojego wstępnej selekcji. Wygląda na to, że po pierwszym wyświetleniu sterowania zostanie zresetowany. Bardzo brzydkim rozwiązaniem byłoby ustawienie wartości przez licznik czasu. Ustawienie go w załadowanym zdarzeniu kontroli użytkownika działa dla mnie w tej przykładowej aplikacji, ale w mojej cięższej rzeczywistej aplikacji nie działa. W każdym razie, wszystko to wydaje się błędne. Czy ktoś zna lepsze rozwiązanie?

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

Odpowiedz

5

Chociaż widok/UserControl ładowane zdarzenie ma miejsce przed ComboBox SelectedItem jest ustawiany na wartość null w mojej aplikacji, zdarzenie ComboBox ładowany jest w rzeczywistości strzelił dwa razy, drugi raz "dość późno". Moje bieżące rozwiązanie, które będę chętnie do rowu lepszy tak, to:

<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

Uratowałeś mi ogromną ilość czasu ...Dzięki wielkie !!! –

2

skończyło się tylko przy użyciu standardowego ComboBox.

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

Jeśli chcesz tego samego (bardzo podobny) Styl jako RibbonComboBox użyć

<ComboBox IsEditable="True" IsReadOnly="True" SelectedItem="{Binding Item}" ItemsSource="{Binding Items}"/> 
Powiązane problemy