2011-04-15 5 views
3

J'ai cette mesure UserControl qui a une liste et un bouton:WPF contrôle personnalisé: DependencyProperty TwoWay Reliure

<UserControl x:Class="WpfApplication1.CustomList" 
     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="300" d:DesignWidth="300"> 
    <Grid> 
     <ListBox Name="listBox1" ItemsSource="{Binding ListSource}" HorizontalAlignment="Right" Width="174" /> 
     <Button Name="ButtonAdd" Content="Add" HorizontalAlignment="Left" Width="101" /> 
    </Grid> 
</UserControl> 

Le code a derrière un DependencyProperty de type IEnumerable et un gestionnaire (onAdd) pour le bouton:

public partial class CustomList : UserControl 
{ 
    public CustomList() 
    { 
     InitializeComponent(); 
    ButtonAdd.Click += new RoutedEventHandler(OnAdd); 
    } 

private void OnAdd(object sender, EventArgs e) 
{ 
    IList<object> tmpList = this.ListSource.ToList(); 
    Article tmpArticle = new Article(); 
    tmpArticle .Name = "g"; 
    tmpList.Add(tmpArticle); 
    ListSource = (IEnumerable<object>) tmpList; 
} 

    public IEnumerable<object> ListSource 
    { 
     get 
     { 
      return (IEnumerable<object>)GetValue(ListSourceProperty); 
     } 
     set 
     { 
      base.SetValue(CustomList.ListSourceProperty, value); 
     } 
    } 

    public static DependencyProperty ListSourceProperty = DependencyProperty.Register(
     "ListSource", 
     typeof(IEnumerable<object>), 
     typeof(CustomList), 
     new PropertyMetadata(OnValueChanged)); 

    private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((CustomList)d).ListSource = (IEnumerable<object>)e.NewValue; 
    } 
} 

Dans le gestionnaire de boutons, j'essaie d'ajouter un article à ListSource (qui est lié aux articles). Ce est la fenêtre où j'utiliser mon UserControl (CustomList):

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:local="clr-namespace:WpfApplication1" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:CustomList ListSource="{Binding Articles, Mode=TwoWay}" Margin="80,0,0,0" /> 
    </Grid> 
</Window> 

Lorsque je clique sur le bouton, les articles deviennent nuls au lieu d'ajouter un article dans la dans la collection des articles. Et la propriété ListSource devient également null. Est-ce que je fais quelque chose de mal ici? Est-ce un comportement attendu? Si oui, quelle serait une manière différente de le faire: Créer un contrôle personnalisé qui aura une liste et un bouton et le gestionnaire pour le bouton va ajouter des objets dans la liste.

Répondre

5

Il y a beaucoup de problèmes ici, mais le problème principal est qu'il existe probablement une incompatibilité de type entre les propriétés sur lesquelles vous essayez d'utiliser TwoWay Binding. Vous n'avez pas répertorié le code pour votre propriété Articles, mais je suppose que c'est probablement quelque chose comme IEnumerable<Article> ou ObservableCollection<Article> et non IEnumerable<object> comme c'est votre propriété ListSource.

Lorsque vous configurez deux voies de reliure et de la valeur cible ne peut pas être reconverti au type de source (IEnumerable<object> ->ObservableCollection<Article>) la propriété source (articles ici) recevront une valeur nulle, qui sera ensuite obtenir poussé retour à travers la liaison à la propriété cible (ListSource ici).

Vous pouvez modifier le type de chaque côté, mais si vous les utilisez avec une liaison TwoWay, les types doivent correspondre.

En général, c'est une mauvaise idée d'utiliser TwoWay Bindings avec des collections. Au lieu de copier et de remplacer l'instance de collection chaque fois que vous souhaitez effectuer une modification, il vous suffit d'ajouter et de supprimer des éléments d'une instance. Étant donné que cette instance est la même collection des deux côtés de la liaison (OneWay), les mises à jour apparaîtront des deux côtés, et si vous utilisez une ObservableCollection, vous pouvez également recevoir des notifications de modification de chaque côté.

Vous devriez également vous débarrasser de votre code OnValueChanged car il ne fait que réinitialiser la propriété à la valeur qui vient d'être définie sur la propriété.

+0

En fait vous aviez raison, ma collection d'articles est une collection Observable d'articles. Maintenant, si elle est correctement comprise, ma propriété ListSource devrait être de type ObservableCollection, n'est-ce pas? Dans ce cas, cependant, je devrais déclarer spécifiquement que ma propriété ListSource est une collection Observable d'articles. Cela peut être un problème si je veux utiliser mon UserControl avec différents types de ObservableCollections (c'est-à-dire ObservableCollection of Persons). Si je me trompe, vous pensez que vous pourriez fournir un échantillon de ce qui serait une meilleure façon de le faire? – Aris

Questions connexes