2014-04-19 11 views
5

Czy ktoś może pokazać mi prosty przykład działania aplikacji WPV MVVM, aby ustawić ItemsSource w combobox B na podstawie SelectedItem z ComboBox A?Potrzebujesz prostego roboczego przykładu ustawienia WPF MVVM ComboBox ItemsSource na podstawie SelectedValue drugiego ComboBox

Wygląda na to, że znalazłem na tej stronie zbyt szybko zbyt skomplikowane.

Jaki jest "właściwy" sposób MVVM, aby to zrobić?

Dziękuję.

EDYTOWANIE Zaktualizowałem, korzystając z przykładu Didiera. Wyciąg z moim XAML:

<ComboBox Name="BrowserStackDesktopOS" ItemsSource="Binding Platforms.AvailableBrowserStackDesktopOSes}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopOSSelectedValue, Mode=TwoWay}"/> 

<ComboBox Name="BrowserStackDesktopOSVersion" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopOSVersions}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopOSVersionSelectedValue, Mode=TwoWay}"/> 

<ComboBox Name="BrowserStackDesktopBrowser" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopBrowsers}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopBrowserSelectedValue, Mode=TwoWay}"/> 

<ComboBox Name="BrowserStackDesktopBrowserVersion" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopBrowserVersions}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopBrowserVersionSelectedValue, Mode=TwoWay}"/> 

a przykładem mojego kodu za:

public string BrowserStackDesktopOSSelectedValue { 
     get { return (string)GetValue(BrowserStackDesktopOSSelectedValueProperty); } 
     set { SetValue(BrowserStackDesktopOSSelectedValueProperty, value); 
       AvailableBrowserStackDesktopOSVersions = AvailableBrowserStackDesktopPlatforms.GetOSVersions(BrowserStackDesktopOSSelectedValue); 
       NotifyPropertyChanged("BrowserStackDesktopOSSelectedValue"); 
     } 
    } 

Jednak kiedy wybrać wartość dla pierwszego ComboBox nic się nie dzieje. Chcę, aby zasób Items następnego ComboBox został wypełniony.

Co zrobiłem źle?

Odpowiedz

8

Zasadniczo należy ujawnić w zbiorze wartości MVVM 2 wartości pól kombi i dwie właściwości dla wybranych wartości. Na początku tylko pierwsza kolekcja, jeśli zapełni się wartościami. Gdy pierwsza wybrana wartość zmieni się, druga kolekcja może zostać wypełniona odpowiednimi wartościami. Oto przykład realizacji:

Kod za:

public partial class MainWindow : Window 
{ 

    public MainWindow() 
    { 
     InitializeComponent(); 

     //Set the data context of the window 
     DataContext = new TestVM(); 
    } 
} 


public class TestVM : INotifyPropertyChanged 
{ 

    #region Class attributes 

    protected static string[] firstComboValues = new string[] { "Choice_1", "Choice_2" }; 

    protected static string[][] secondComboValues = 
     new string[][] { 
       new string[] { "value_1_1", "value_1_2", "value_1_3" }, 
       new string[] { "value_2_1", "value_2_2", "value_2_3" } 
     }; 


    #endregion 

    #region Public Properties 

    #region FirstSelectedValue 

    protected string m_FirstSelectedValue; 

    /// <summary> 
    /// 
    /// </summary> 
    public string FirstSelectedValue 
    { 
     get { return m_FirstSelectedValue; } 
     set 
     { 
      if (m_FirstSelectedValue != value) 
      { 
       m_FirstSelectedValue = value; 
       UpdateSecondComboValues(); 
       NotifyPropertyChanged("FirstSelectedValue"); 
      } 
     } 
    } 

    #endregion 

    #region SecondSelectedValue 

    protected string m_SecondSelectedValue; 

    /// <summary> 
    /// 
    /// </summary> 
    public string SecondSelectedValue 
    { 
     get { return m_SecondSelectedValue; } 
     set 
     { 
      if (m_SecondSelectedValue != value) 
      { 
       m_SecondSelectedValue = value; 
       NotifyPropertyChanged("SecondSelectedValue"); 
      } 
     } 
    } 

    #endregion 

    #region FirstComboValues 

    protected ObservableCollection<string> m_FirstComboValues; 

    /// <summary> 
    /// 
    /// </summary> 
    public ObservableCollection<string> FirstComboValues 
    { 
     get { return m_FirstComboValues; } 
     set 
     { 
      if (m_FirstComboValues != value) 
      { 
       m_FirstComboValues = value; 
       NotifyPropertyChanged("FirstComboValues"); 
      } 
     } 
    } 

    #endregion 

    #region SecondComboValues 

    protected ObservableCollection<string> m_SecondComboValues; 

    /// <summary> 
    /// 
    /// </summary> 
    public ObservableCollection<string> SecondComboValues 
    { 
     get { return m_SecondComboValues; } 
     set 
     { 
      if (m_SecondComboValues != value) 
      { 
       m_SecondComboValues = value; 
       NotifyPropertyChanged("SecondComboValues"); 
      } 
     } 
    } 

    #endregion 

    #endregion 

    public TestVM() 
    { 
     FirstComboValues = new ObservableCollection<string>(firstComboValues); 
    } 

    /// <summary> 
    /// Update the collection of values for the second combo box 
    /// </summary> 
    protected void UpdateSecondComboValues() 
    { 
     int firstComboChoice; 
     for (firstComboChoice = 0; firstComboChoice < firstComboValues.Length; firstComboChoice++) 
     { 
      if (firstComboValues[firstComboChoice] == FirstSelectedValue) 
       break; 
     } 


     if (firstComboChoice == firstComboValues.Length)// just in case of a bug 
      SecondComboValues = null; 
     else 
      SecondComboValues = new ObservableCollection<string>(secondComboValues[firstComboChoice]); 

    } 


    #region INotifyPropertyChanged implementation 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    #endregion 
} 

i związany XAML

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Name="window" x:Class="Testing1.MainWindow"> 

    <Grid> 

     <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Width=" 300"> 
      <Grid.RowDefinitions> 
       <RowDefinition/> 
       <RowDefinition Height="10"/> 
       <RowDefinition/> 
      </Grid.RowDefinitions> 

      <ComboBox x:Name="FirstOne" ItemsSource="{Binding FirstComboValues}" SelectedItem="{Binding FirstSelectedValue, Mode=TwoWay}"/> 

      <ComboBox x:Name="SecondOne" ItemsSource="{Binding SecondComboValues}" SelectedItem="{Binding SecondSelectedValue, Mode=TwoWay}" Grid.Row="2"/> 

     </Grid> 

    </Grid> 

</Window> 

Jak widać SelectedValue właściwości pól kombi są zbindowanych w trybie TwoWay więc kiedy SelectedValue Właściwość pola kombi zmienia się, zmienia wartość po stronie VM. I w metodzie FirstSelectedValue ustawia się metodę ustawiania właściwości UpdateSecondComboValues(), aby zaktualizować wartości dla drugiego pola kombi.

EDIT:

Zdarza się, bo miesza zarówno INotifPropertyChanged i DependencyObject. Powinieneś wybrać jedną z nich. Zwykle implementujesz INotifyPropertyChanged w swojej maszynie wirtualnej, a kod w ustawiaczu właściwości zadziała.

Jeśli jednak dziedziczysz z DependencyObject, nie powinieneś pisać żadnego kodu w setter/getter. Nigdy nie zostanie wywołane przez wiązanie TwoWay. Po prostu wywoła GetValue (...) wewnętrznie. Aby móc wykonać to działanie na DependencyProperty zmienić należy ją zadeklarować odmiennie z właściwości zmieniono obsługi:

#region BrowserStackDesktopOSSelectedValue 

/// <summary> 
/// BrowserStackDesktopOSSelectedValue Dependency Property 
/// </summary> 
public static readonly DependencyProperty BrowserStackDesktopOSSelectedValue Property = 
    DependencyProperty.Register("BrowserStackDesktopOSSelectedValue ", typeof(string), typeof(YourVM), 
     new FrameworkPropertyMetadata((string)null, 
      new PropertyChangedCallback(OnBrowserStackDesktopOSSelectedValue Changed))); 

/// <summary> 
/// Gets or sets the BrowserStackDesktopOSSelectedValue property. This dependency property 
/// indicates .... 
/// </summary> 
public string BrowserStackDesktopOSSelectedValue 
{ 
    get { return (string)GetValue(BrowserStackDesktopOSSelectedValue Property); } 
    set { SetValue(BrowserStackDesktopOSSelectedValue Property, value); } 
} 

/// <summary> 
/// Handles changes to the BrowserStackDesktopOSSelectedValue property. 
/// </summary> 
private static void OnBrowserStackDesktopOSSelectedValue Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    YourVM target = (YourVM)d; 
    string oldBrowserStackDesktopOSSelectedValue = (string)e.OldValue; 
    string newBrowserStackDesktopOSSelectedValue = target.BrowserStackDesktopOSSelectedValue ; 
    target.OnBrowserStackDesktopOSSelectedValue Changed(oldBrowserStackDesktopOSSelectedValue , newBrowserStackDesktopOSSelectedValue); 
} 

/// <summary> 
/// Provides derived classes an opportunity to handle changes to the BrowserStackDesktopOSSelectedValue property. 
/// </summary> 
protected virtual void OnBrowserStackDesktopOSSelectedValue Changed(string oldBrowserStackDesktopOSSelectedValue , string newBrowserStackDesktopOSSelectedValue) 
{ 
    //Here write some code to update your second ComboBox content. 
    AvailableBrowserStackDesktopOSVersions = AvailableBrowserStackDesktopPlatforms.GetOSVersions(BrowserStackDesktopOSSelectedValue); 
} 

#endregion 

Przy okazji zawsze używam Dr WPF snippets napisać PRR tak to idzie o wiele szybciej.

+0

Dzięki Didier, zobacz moje EDYCJA powyżej. –

+0

OK. Edytowałem swoją odpowiedź. – Dmitry

+0

Dzięki Didier, to zadziałało. –

Powiązane problemy