2008-12-15 9 views
2

Feignons je le XAML suivant ...Silverlight Databinding - Liaison d'un ValueConverter à une propriété sur une vue modèle

<UserControl.Resources> 
    <local:ViewModel x:Name="viewModel" /> 
    <local:LoadChildrenValueConverter x:Name="valueConverter" /> 
</UserControl.Resources> 

<UserControl.DataContext> 
    <Binding Source="{StaticResource viewModel}" /> 
</UserControl.DataContext> 

<Grid x:Name="LayoutRoot" Background="White"> 
    <control:TreeView ItemsSource="{Binding Root}"> 
     <control:TreeView.ItemTemplate> 
      <control:HierarchicalDataTemplate ItemsSource="{Binding Converter={StaticResource valueConverter}}"> 
       <TextBlock Text="{Binding}" /> 
      </control:HierarchicalDataTemplate> 
     </control:TreeView.ItemTemplate> 
    </control:TreeView> 
</Grid> 

... et le code suivant aller avec elle ...

 
using System; 
using System.Collections.ObjectModel; 
using System.Windows.Data; 

namespace SilverlightViewModelSpike 
{ 
    public class ViewModel 
    { 
     public ViewModel() 
     { 
      Root = new ObservableCollection() { "Item 1", "Item 2", "Item 3", }; 
     } 

     public ObservableCollection Root { get; private set; }   
    } 

    public class LoadChildrenValueConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return new ObservableCollection() { "Item 1", "Item 2", "Item 3", }; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

Cela fonctionne comme prévu, mais il se sent mal que j'ai deux classes distinctes qui sont nécessaires pour saisir les données nécessaires à mon affichage (imaginez que ViewModel et LoadChildrenValueConverter extraient des données d'un service Web au lieu de renvoyer des données codées en dur). Y a-t-il une meilleure solution ici? Je pensais peut-être quelque chose comme ça ...

 
using System; 
using System.Collections.ObjectModel; 
using System.Windows.Data; 

namespace SilverlightViewModelSpike 
{ 
    public class ViewModel 
    { 
     public ViewModel() 
     { 
      Root = new ObservableCollection() { "Item 1", "Item 2", "Item 3", }; 
      ValueConverter = new LoadChildrenValueConverter(); 
     } 

     public ObservableCollection Root { get; private set; } 
     public LoadChildrenValueConverter ValueConverter { get; private set; } 
    } 

    public class LoadChildrenValueConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return new ObservableCollection() { "Item 1", "Item 2", "Item 3", }; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

... mais je ne peux pas obtenir cette ligne de travail ...

<control:HierarchicalDataTemplate ItemsSource="{???}">

... et même que Cela ne semble pas être une bonne solution. Est-ce que quelqu'un a une bonne solution propre pour cela?

Répondre

4

Puisque vous utilisez un ViewModel pour vous asseoir entre votre modèle actuel et votre vue, je me demande s'il est plus facile d'implémenter la logique IValueConverter directement là-dedans. Un peu comme:

public class ViewModel 
{ 
    public ObservableCollection Root { get; set: } 

    public ObservableCollection Children 
    { 
     get { /* return children items */ } 
    } 
} 

alors vous pouvez simplement lier directement à votre deuxième propriété:

<control:HierarchicalDataTemplate ItemsSource="{Binding Children}"> 

Je pense que le but principal d'un objet ViewModel est de limiter le nombre de « trucs » (tels que IValueConverters) vous devez tirer pour obtenir les données dont vous avez besoin du modèle original. Puisque vous en avez un, vous pourriez aussi bien en faire usage.

Modifier 1

... et bien sûr maintenant que je relis votre post, je vois qu'il ya plus à lui. Vous obtenez les enfants pour chaque article de votre collection "Root".

Comment implémenter IValueConverter en tant qu'instance statique dans votre ViewModel lui-même?

public class ViewModel : IValueConverter 
{ 
    public static readonly IValueConverter ChildrenConverter 
     = new LoadChildrenValueConverter(); 
} 

Maintenant, vous devriez être en mesure de dire:

<control:HierarchicalDataTemplate 
    ItemsSource="{Binding Converter={x:Static local:ViewModel.ChildrenConverter}}"> 

Edit 2

Ok, vous utilisez Silverlight si {x: statique} n'est pas disponible pour vous. La seule autre option que je peux penser qui vous permettra de réutiliser une ressource statique au lieu d'avoir à déclarer deux est d'implémenter l'IValueConverter directement dans votre ViewModel. Ce n'est pas bon si vous devez faire plusieurs types de conversion, mais si votre ViewModel est très focalisé, alors il pourrait faire le travail.Alors:

public class ViewModel : IValueConverter 
{ 
    // move your Convert and ConvertBack methods into here 
} 

Maintenant, vous pouvez faire ceci:

<control:HierarchicalDataTemplate 
    ItemsSource="{Binding Converter={StaticResource ViewModel}}"> 
+0

C'est un peu ce que je veux dire. Cependant, je ne pense pas que Silverlight permette x: Static dans les bindings. N'est-ce pas vrai? – herbrandson

+0

Ah vous avez raison. Je n'avais pas remarqué que vous aviez étiqueté votre question comme Silverlight. Je vais ajouter une option supplémentaire à la réponse juste au cas où c'est viable pour vous. –

+1

Merci pour l'aide. L'idée que vous présentez dans Edit2 est réellement là où j'ai commencé. J'espérais qu'il y avait une solution plus propre, mais je ne semble pas l'être à ce stade. Cela aide certains à voir quelqu'un d'autre arriver à la même conclusion. Au moins, je ne me sens pas comme une solution stupide :) – herbrandson

0

Désolé les gars, je suis un peu confus au sujet de ce que vous essayez de faire ici ... Quoi qu'il en soit, à partir du titre, il sonne comme si vous Vous voulez une propriété dans votre convertisseur de valeur à une propriété dans votre convertisseur de valeur. Tout d'abord jeter un oeil à un article que je vous ai écrit pour expliquer exactement comment vous pouvez faire: http://nick-howard.blogspot.com/2011/06/silverlight-4-value-converter.html

Alors ce que vous feriez est de créer une propriété de dépendance ObvervableCollection dans votre LoadChildrenValueConverter, pour des arguments que nous appellerons enfants.

Ensuite, dans votre XAML vous pouvez changer le LoadChildrenValueConverter à quelque chose comme ceci:

De cette façon, vous n'appelez le service Web une fois de votre modèle de vue, et vous êtes ensuite partager cette ObvervableCollection dans votre modèle de vue avec votre convertisseur de valeur.

Espérons que ça aide.

Questions connexes