2010-10-07 4 views
14

J'essaie de créer un contrôle utilisateur avec des propriétés de dépendance à lier. En interne, j'ai un ComboBox qui est lié à ces mêmes propriétés, mais la liaison ne fonctionne que dans un sens. Le ComboBox remplit à partir du ItemsSource, mais SelectedItem n'est pas mis à jour vers le viewmodel auquel je suis lié.Comment faire pour que les propriétés de dépendance de mon contrôle utilisateur WPF mettent à jour mon modèle de vue?

Un exemple simplifié:

C'est le modèle en vue de se lier avec le contrôle de l'utilisateur:

public class PeopleViewModel : INotifyPropertyChanged 
{ 
    public PeopleViewModel() 
    { 
     People = new List<string>(new [] {"John", "Alfred","Dave"}); 
     SelectedPerson = People.FirstOrDefault(); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private IEnumerable<string> _people; 
    public IEnumerable<string> People 
    { 
     get { return _people; } 
     set 
     { 
      _people = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("People")); 
      } 
     } 
    } 

    private string _selectedPerson; 
    public string SelectedPerson 
    { 
     get { return _selectedPerson; } 
     set 
     { 
      _selectedPerson = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("SelectedPerson")); 
      } 
     } 
    } 
} 

Ceci est le contrôle de l'utilisateur:

<UserControl x:Class="PeopleControlTest.PeopleControl" 
     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" 
     mc:Ignorable="d" d:DesignHeight="56" d:DesignWidth="637"> 
<StackPanel > 
    <ComboBox Margin="11" 
       ItemsSource="{Binding BoundPeople, RelativeSource={RelativeSource AncestorType=UserControl}}" 
       SelectedItem="{Binding BoundSelectedPerson, RelativeSource={RelativeSource AncestorType=UserControl}}"/> 
</StackPanel> 

avec le code derrière

public partial class PeopleControl : UserControl 
{ 
    public PeopleControl() 
    { 
     InitializeComponent(); 
    } 

    public static readonly DependencyProperty BoundPeopleProperty = 
     DependencyProperty.Register("BoundPeople", typeof(IEnumerable<string>), typeof(PeopleControl), new UIPropertyMetadata(null)); 

    public static readonly DependencyProperty BoundSelectedPersonProperty = 
     DependencyProperty.Register("BoundSelectedPerson", typeof(string), typeof(PeopleControl), new UIPropertyMetadata("")); 

    public IEnumerable<string> BoundPeople 
    { 
     get { return (IEnumerable<string>)GetValue(BoundPeopleProperty); } 
     set { SetValue(BoundPeopleProperty, value); } 
    } 

    public string BoundSelectedPerson 
    { 
     get { return (string)GetValue(BoundSelectedPersonProperty); } 
     set { SetValue(BoundSelectedPersonProperty, value); } 
    } 
} 

Et voilà comment je lie le contrôle de l'utilisateur dans la fenêtre principale (avec le contexte de données Windows définie à une instance du viewmodel)

<Window x:Class="PeopleControlTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:controls="clr-namespace:PeopleControlTest" 
    Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <controls:PeopleControl 
      BoundPeople="{Binding People}" 
      BoundSelectedPerson="{Binding SelectedPerson}"/> 
    </Grid> 
</Window> 

Le combobox dans le contrôle utilisateur remplit les noms, mais lorsque je sélectionne un nom différent, cela n'est pas remis à jour dans le modèle de vue. Une idée de ce qui me manque ici?

Merci!

Répondre

19

Certaines propriétés se lient par défaut (y compris SelectedItem) mais pas votre BoundSelectedPerson. Vous pouvez régler le mode de la liaison:

<controls:PeopleControl 
      BoundPeople="{Binding People}" 
      BoundSelectedPerson="{Binding SelectedPerson, Mode=TwoWay}"/> 

Ou vous pouvez le faire TwoWay par défaut en définissant un drapeau sur le DependencyProperty:

public static readonly DependencyProperty BoundSelectedPersonProperty = 
     DependencyProperty.Register("BoundSelectedPerson", typeof(string), typeof(PeopleControl), new FrameworkPropertyMetadata("",FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 
+0

Très bien, merci, ça marche !!! Pour une raison quelconque, j'ai pensé que j'avais lu que tous les DP fonctionnent deux par défaut. J'utilisais aussi UIPropertyMetadata, sur lequel je ne pouvais pas trouver cette option. – Stefan

+0

_ (Cette solution est très bien, je veux juste ajouter une note pour les personnes qui pourraient avoir le même problème que moi et trouver leur chemin ici en cherchant une solution.) _ La propriété que vous liez à une propriété de dépendance de UserControl doit avoir une méthode set(). – skst

Questions connexes