Подтвердить что ты не робот

Связывание в WPF с элементом массива, заданным свойством

Скажем, у меня есть некоторые текстовые блоки в моем пользовательском интерфейсе, примерно так:

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

и в моем коде позади у меня есть что-то вроде этого:

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;
    }
}

Первые два TextBlocks отображаются отлично для меня, отображая 2 и 'cake' соответственно. Третий не выполняет то, что я хотел бы, а именно использовать свойство DessertIndex для индексации в этот массив, а также отображать "cake". Я немного искал здесь на SO для аналогичного вопроса, но не нашел его. В конечном счете, я не хочу указывать такие значения, как 2 в моем .xaml файле, и хотел бы полагаться на свойство вместо этого для индексации в этот массив. Это возможно? Если да, то что я делаю неправильно здесь?


EDIT:

Так что я более тесно - ситуация, когда данные представляют собой Список этих объектов [], и я использую вышеуказанный StackPanel как часть DataTemplate для ListBox. Таким образом, идея, как предлагает Марк Хит, использовать свойство, которое разделяет массив, похоже, не работает так, как я бы хотел. Идеи?

4b9b3361

Ответ 1

Другой альтернативой является использование MultiBinding с конвертером:

<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>

Затем в коде-коде конвертер определяется примерно так:

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();
        }
    }
}

Ответ 2

если вы столкнулись с проблемой наличия свойства DesertIndex в вашем DataContext, почему бы не свойство, которое разделяет массив Food с 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" };
    }
}

то вы можете напрямую связать с ним:

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

Это по существу подход "MVVM": сделать объект datacontext имеющими свойства, которые подходят для привязки.