web-dev-qa-db-fra.com

Liaison dans WPF à l'élément du tableau spécifié par la propriété

Disons que j'ai des TextBlocks sur mon interface utilisateur, quelque chose comme ça:

<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 ça:

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 bien pour moi, affichant respectivement 2 et "gâteau". Le troisième n'accomplit pas ce que j'aimerais, à savoir utiliser la propriété DessertIndex pour indexer dans ce tableau et également afficher "gâteau". J'ai fait une petite 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 de valeurs comme 2 dans mon fichier .xaml et je voudrais me fier sur une propriété pour l'indexation dans ce tableau. Est-ce possible? Si oui, que fais-je de mal ici?


ÉDITER:

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

28
itsmatt

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>

Ensuite, dans le code-behind, le convertisseur est défini quelque chose 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();
        }
    }
}
29
Colin Thomsen

si vous avez la difficulté d'avoir une propriété DesertIndex sur votre DataContext, pourquoi pas une propriété qui déréférence le tableau Food 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 vous y lier directement:

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

Il s'agit essentiellement de l'approche "MVVM": faire en sorte que l'objet datacontext ait des propriétés qui conviennent parfaitement à la liaison.

13
Mark Heath