2010-08-12 2 views
3

J'apprends wpf mvvm et j'ai eu du mal avec ce que je pense être probablement simple mais qui n'a pas été capable de résoudre tout seul. Ce que je veux, c'est pouvoir sélectionner un élément dans une zone de liste déroulante remplie, puis remplir une autre zone de liste déroulante en fonction de cette sélection. Je n'arrive pas à charger la seconde combobox en réponse à une sélection.Remplir un combobox basé sur la sélection d'un autre

J'ai inclus un exemple avec 2 comboboxes et un bloc de texte. Lorsque je lance l'application et sélectionne un élément dans le premier combo, le bloc de texte est mis à jour en fonction de la liaison, mais je ne sais pas où appeler le code pour mettre à jour la deuxième liste déroulante.

J'ai essayé d'ajouter l'appel à l'accesseur de propriété SelectedString, mais cela ne semble jamais être appelé. Je suis sûr qu'il me manque quelque chose de simple, mais j'ai besoin de quelqu'un pour aider à lever le voile!

J'ai essayé des suggestions sur d'autres messages mais jusqu'ici j'ai échoué.

Voici le XAML pour la vue:

<Window x:Class="ThrowAwayMVVMApp.Views.MainView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Main Window" Height="400" Width="800"> 

    <DockPanel> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="60*" /> 
       <RowDefinition Height="282*" /> 
      </Grid.RowDefinitions> 
      <!-- Add additional content here --> 
      <ComboBox ItemsSource="{Binding MyStrings}" SelectedItem="{Binding Path=SelectedString, Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="18,24,0,0" Name="comboBox1" VerticalAlignment="Top" Width="204" /> 
      <TextBlock Text="{Binding SelectedString}" Height="23" HorizontalAlignment="Left" Margin="276,24,0,0" Name="textBlock1" VerticalAlignment="Top" Width="227" Background="#FFFAE7E7" /> 
      <ComboBox ItemsSource="{Binding ResultStrings}" Height="23" HorizontalAlignment="Left" Margin="543,25,0,0" Name="comboBox2" VerticalAlignment="Top" Width="189" /> 
     </Grid> 
    </DockPanel> 
</Window> 

Voici le modèle de vue:

public class MainViewModel : ViewModelBase 
{ 
    public MainViewModel() 
    { 
     this.MyStrings = new ObservableCollection<string> 
      { 
       "One", 
       "Two", 
       "Three", 
       "Four", 
       "Five" 
      }; 
    } 

    public ObservableCollection<string> MyStrings { get; set; } 
    public ObservableCollection<string> ResultStrings { get; set; } 

    public string SelectedString 
    { 
     get { return (string)GetValue(SelectedStringProperty); } 
     set 
     { 
      SetValue(SelectedStringProperty, value); 
      this.ResultStrings = getResultStrings(value); 
     } 
    } 

    // Using a DependencyProperty as the backing store for SelectedString. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty SelectedStringProperty = 
     DependencyProperty.Register("SelectedString", typeof(string), typeof(MainViewModel), new UIPropertyMetadata("")); 


    private ObservableCollection<string> getResultStrings(string input) 
    { 
     ObservableCollection<string> result = null; 

     if (input == "Three") 
     { 
      result = new ObservableCollection<string> { "Six", "Seven", "Eight" }; 
     } 
     else 
     { 
      result = new ObservableCollection<string> { "Nine", "Ten", "Eleven" }; 
     } 

     return result; 
    } 
} 
+0

Pourquoi avez-vous un DP déclaré au sein de votre ViewModel, généralement sa destinée à aller dans le contrôle que vous liez à? – Agies

Répondre

2

La mise en œuvre de la propriété de dépendance SelectedString est erroné: vous devez vous inscrire PropertyChangedCallback pour être informé lorsque le DP est accédé directement et non avec l'ensemble de propriétés CLR (voir http://msdn.microsoft.com/en-us/library/system.windows.propertychangedcallback.aspx); De cette façon, vous pouvez modifier la collection associée même si le DP est utilisé directement.

Lors de la liaison avec une propriété de dépendance (comme SelectedString), la liaison WPF n'utilise pas l'accesseur de propriété CLR, donc vous ne recevez jamais getResultStrings appelé. Par ailleurs, j'utiliserais une approche POCO sur View Models, implémentant INotifyPropertyChanged: DP est difficile à écrire et ajoute beaucoup de bruit aux machines virtuelles (autre qu'une mauvaise dépendance sur System.Windows).

Jetez un oeil à ce billet de blog pour une comparaison approfondie: http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html

0

Essayez

private string selectedString; 
public string SelectedString 
{ 
    get { return selectedString; } 
    set 
    { 
     if (selectedString == value) return; 
     selectedString = value; 
     // Required for the UI to know the change was successful 
     RaisePropertyChanged("SelectedString"); 
     LoadStringResults(value); 
    } 
} 

private ObservableCollection<string> resultStrings; 
public ObservableCollection<string> ResultStrings 
{ 
    get { return resultStrings; } 
    set 
    { 
     if (resultStrings== value) return; 
     resultStrings= value; 
     // Required for databinding to know that ResultStrings changed 
     // Previously you changed this property without updating the UI 
     RaisePropertyChanged("ResultStrings"); 
    } 
} 

private void LoadStringResults(string input) 
{ 
    ObservableCollection<string> result = null; 

    if (input == "Three") 
    { 
     result = new ObservableCollection<string> { "Six", "Seven", "Eight" }; 
    } 
    else 
    { 
     result = new ObservableCollection<string> { "Nine", "Ten", "Eleven" }; 
    } 

    ResultStrings = result; 
}