2014-04-19 23 views
5

'un SelectedValue'sine dayalı WPF MVVM ComboBox ItemsSource öğesinin ayarlanmasının BASİT çalışma örneğine ihtiyaç duyan herkes WPF MVVM uygulaması için ComboBox A'nın SelectedItem öğesini kullanarak ComboBox B öğelerini ayarlamak için basit bir çalışma örneği gösterebilir mi?İkinci ComboBox

Bu sitede bulduğumdan çok hızlı bir şekilde tümüyle karmaşık hale geldiğini görüyorum.

Bunu yapmanın "doğru" MVVM yolu nedir?

Teşekkür ederiz.

EDIT Didier örneğini kullanarak güncelleştirdim. benim XAML bir özü:

<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}"/> 

Ve arkasında benim koduna örnek: Ben ilk ComboBox hiçbir şey için bir değer seçtiğinizde

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

Ancak olmuyor. Bir sonraki ComboBox'ın Itemsource'unun doldurulmasını istiyorum.

Neyi yanlış yaptım?

cevap

8

Temelde, birleşik kutular için MVVM 2 değer koleksiyonunuza ve seçilen değerler için iki özelliğe sahip olmanız gerekir. Başlangıçta, değerlerle dolu olması halinde ilk koleksiyon. İlk seçilen değer değiştiğinde, ikinci koleksiyon uygun değerlerle doldurulabilir.

Kod arkasında:

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 
} 

Ve

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

Eğer açılan kutulardaki SelectedValue özelliklerini görebileceğiniz gibi öylesine SelectedValue TwoWay modunda binded edilir ilişkili XAML İşte uygulamasına bir örnektir açılan kutunun özelliği, VM tarafındaki değeri değiştirir. Ve FirstSelectedValue özellik ayarlayıcıda UpdateSecondComboValues() ikinci birleşik kutu için değerleri güncellemek için yöntem çağrılır.

DÜZENLEME: Eğer INotifPropertyChanged ve DependencyObject hem karışık çünkü

Olur. Onlardan birini seçmelisin. Genellikle, VM'nize INotifyPropertyChanged uygularsınız ve özellik kümesindeki kod çalışır.

Ancak, DependencyObject öğesinden devralınırsanız, setter/getter içine herhangi bir kod yazmamalısınız. TwoWay ciltleme tarafından asla çağrılmayacak. Sadece GetValue (...) 'i dahili olarak arayacaktır. DependencyProperty üzerinde bir eylem bir özellik değiştirilen işleyicisi ile farklı şekilde ilan etmeli değiştirmek yürütmek edebilmek için:

#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 

çok daha hızlı gider o yüzden hep DPs yazmak için Dr WPF snippets kullanmak arada.

+0

Teşekkürler Didier, yukarıdaki EDIT'ime bakın. –

+0

Tamam Cevabımı düzenledim. – Dmitry

+0

Teşekkürler Didier, bu işe yaradı. –