2
Public Class View
    Public Property Items As String() = {"One", "Two", "Three"}
    Public Property Index As Integer = 0
End Class

It's instance is set as DataContext of this XAML:

<Window>
    <StackPanel>
        <ListBox ItemsSource="{Binding Items}" SelectedIndex="{Binding Index}"/>
        <Label Content="{Binding Items[Index]}"/>
    </StackPanel>
</Window>

But this doesn't work.

<Label Content="{Binding Items[{Binding Index}]}"/>

This neither.

<Label Content="{Binding Items[0]}"/>

This works.

Is there any solution except making extra property in view? Something directly in XAML?

3 Answers3

3

I'm afraid it's not possible without some code-behind, but using reflection and dynamic, you can create a converter that can do this (it would be possible without dynamic, but more complex):

public class IndexerConverter : IValueConverter
{
    public string CollectionName { get; set; }
    public string IndexName { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Type type = value.GetType();
        dynamic collection = type.GetProperty(CollectionName).GetValue(value, null);
        dynamic index = type.GetProperty(IndexName).GetValue(value, null);
        return collection[index];
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Put following into resources:

<local:IndexerConverter x:Key="indexerConverter" CollectionName="Items" IndexName="Index" />

and use it like this:

<Label Content="{Binding Converter={StaticResource indexerConverter}}"/>

EDIT: The previous solution doesn't update properly when the values change, this one does:

public class IndexerConverter : IMultiValueConverter
{
    public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((dynamic)value[0])[(dynamic)value[1]];
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

In resources:

<local:IndexerConverter x:Key="indexerConverter"/>

Usage:

<Label>
    <MultiBinding Converter="{StaticResource indexerConverter}">
        <Binding Path="Items"/>
        <Binding Path="Index"/>
    </MultiBinding>
</Label>
svick
  • 236,525
  • 50
  • 385
  • 514
  • I don't think this converter will be called if either the collection or the index changes. – Rick Sladkey Apr 23 '11 at 21:42
  • @Rick, yeah, you're right, see updated solution. Of course, for this to work, `View` would have to implement `INotifyPropertyChanged` (or use dependency properties). – svick Apr 23 '11 at 22:07
  • Do you happen to know if it is possible to modify this converter to also be able to write data back to the viewmodel? – pquest Oct 08 '15 at 19:14
0

What you write in the binding markup extension is assigned to the Path property by default, this property is a string so any dynamic content you refer to inside it will not be evaluated. There is no simple XAML-only method to do what you try to do.

H.B.
  • 166,899
  • 29
  • 327
  • 400
0

Why don't use this:

<StackPanel>
        <ListBox Name="lsbItems" ItemsSource="{Binding Items}" SelectedIndex="{Binding Index}"/>
        <Label Content="{Binding ElementName=lsbItems, Path=SelectedItem}"/>
</StackPanel>
IVerzin
  • 868
  • 7
  • 9