2010-11-04 6 views
25

Say J'ai quelques TextBlocks sur mon interface utilisateur, quelque chose comme ceci:de liaison dans WPF à l'élément de tableau spécifié par la propriété

<StackPanel Orientation="Vertical"> 
    <TextBlock Text="{Binding DessertIndex}" /> 
    <TextBlock Text="{Binding Food[2]}" /> 
    <TextBlock Text="{Binding Food[{Binding DessertIndex}]}" /> 
</StackPanel> 

et dans mon code derrière j'ai quelque chose comme ceci:

public partial class MainWindow : Window 
{ 
    public int DessertIndex 
    { 
     get { return 2; } 
    } 

    public object[] Food 
    { 
     get 
     { 
      return new object[]{"liver", "spam", "cake", "garlic" }; 
     } 
    } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = this; 
    } 
} 

Les deux premiers TextBlocks s'affichent très bien pour moi, affichant respectivement 2 et 'cake'. Le troisième n'accomplit pas ce que je veux, à savoir utiliser la propriété DessertIndex pour indexer dans ce tableau et afficher 'cake'. J'ai fait un peu de recherche ici sur SO pour une question similaire mais je n'en ai pas trouvé. En fin de compte, je ne veux pas spécifier des valeurs comme 2 dans mon fichier .xaml et je voudrais me fier à une propriété pour l'indexer dans ce tableau. Est-ce possible? Si oui, qu'est-ce que je fais mal ici?


EDIT:

Alors ce que j'ai plus près est une situation où les données sont une liste de ces objets [] et je l'utilise ci-dessus StackPanel dans le cadre d'un DataTemplate pour une ListBox. Donc, l'idée, comme Mark Heath suggère ci-dessous, d'utiliser une propriété qui déréférence le tableau ne semble pas fonctionner comme je le voudrais. Des idées?

Répondre

26

Une autre alternative consiste à utiliser MultiBinding avec un convertisseur:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication1" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel Orientation="Vertical"> 
     <StackPanel.Resources> 
      <local:FoodIndexConverter x:Key="foodIndexConverter" /> 
     </StackPanel.Resources> 
     <TextBlock Text="{Binding DessertIndex}" /> 
     <TextBlock Text="{Binding Food[2]}" /> 
     <TextBlock> 
       <TextBlock.Text> 
        <MultiBinding Converter="{StaticResource foodIndexConverter}"> 
         <Binding Path="DessertIndex" /> 
         <Binding Path="Food"/> 
        </MultiBinding> 
       </TextBlock.Text> 
     </TextBlock> 
    </StackPanel> 
</Window> 

Puis dans le code-behind, le convertisseur est défini comme ceci:

namespace WpfApplication1 
{ 
    public class FoodIndexConverter : IMultiValueConverter 
    { 
     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (values == null || values.Length != 2) 
       return null; 

      int? idx = values[0] as int?; 
      object[] food = values[1] as object[]; 

      if (!idx.HasValue || food == null) 
       return null; 

      return food[idx.Value]; 
     } 

     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 
+0

Merci Colin - cela fonctionne très bien pour mon application de test et je suppose que ça va marcher aussi bien dans la réalité. Ça a été une bonne journée - j'ai appris quelque chose de vraiment cool de ta part. :) – itsmatt

+2

Vous pourriez être tenté d'essayer quelque chose de différent en utilisant un ConverterParameter pour éviter la multi-liaison. Malheureusement, cela ne mènera nulle part, car ConverterParameter ne peut pas utiliser une liaison car ce n'est pas un DependencyProperty, et vous devez utiliser MultiBinding –

10

si vous allez la peine d'avoir une propriété DesertIndex sur votre DataContext, pourquoi pas une propriété qui déréférence le tableau alimentaire avec DesertIndex:

public object SelectedFood 
{ 
    get { return Food[DessertIndex]; } 
}  

public int DessertIndex 
{ 
    get { return 2; } 
} 

public object[] Food 
{ 
    get 
    { 
     return new object[]{"liver", "spam", "cake", "garlic" }; 
    } 
} 

alors vous pouvez lier directement à cette:

<TextBlock Text="{Binding SelectedFood}" /> 

Il s'agit essentiellement de l'approche "MVVM": faites en sorte que l'objet datacontext possède les propriétés qui conviennent à la liaison.

+0

Mark, Merci pour votre réponse. Voir ma modification à la question d'origine pour plus de détails. Essentiellement, j'ai affaire à un ListBox et à une liste de ces objets [], donc je ne sais pas comment faire le déréférencement comme vous le suggérez dans ce contexte. Les données ne m'appartiennent pas et je dois m'en occuper comme c'est le cas. Des idées? – itsmatt

+0

oui je me suis demandé si cela pourrait être le cas. –