34

Say I've got some TextBlocks on my UI, something like so:

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

and in my code behind I've got something like this:

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

The first two TextBlocks display fine for me, displaying 2 and 'cake' respectively. The third one doesn't accomplish what I'd like, namely use the DessertIndex property to index into that array and also display 'cake'. I did a little searching here on SO for a similar question but didn't find one. Ultimately, I don't want to specify values like 2 in my .xaml file and would like to rely upon a property instead for indexing into that array. Is this possible? If so, what am I doing wrong here?


EDIT:

So what I more closely have is a situation where the data is a List of these object[] and I'm using the above StackPanel as part of a DataTemplate for a ListBox. So the idea, as Mark Heath suggests below, of using a property that dereferences the array doesn't seem to work as I'd want. Ideas?

1
  • The "dereferencing" should work. List or not. Commented Mar 4, 2024 at 4:56

3 Answers 3

32

Another alternative is to use MultiBinding with a converter:

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

Then in the code-behind, the converter is defined something like this:

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();
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Colin - this works very well for my test app and suspect it'll work just as well in the real thing. It's been a good day - I learned something really cool from you. :)
You may be tempted to try something different using a ConverterParameter to avoid the multibinding. Unfortunately, that will lead nowhere, as the ConverterParameter cannot use a binding as it's not a DependencyProperty, and you must use MultiBinding
17

if you are going to the trouble of having a DessertIndex property on your DataContext, why not a property that dereferences the Food array with DessertIndex:

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

public int DessertIndex
{
    get { return 2; }
}

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

then you can bind directly to that:

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

This is essentially the "MVVM" approach: make the datacontext object have properties that are just right for binding to.

2 Comments

Mark, thanks for your response. See my edit to the original question for more detail. Essentially I'm dealing with a ListBox and a List of these object[]'s so I don't know how to make the dereferencing as you suggest work in this context. The data isn't mine and I've got to deal with it as it is. Ideas?
I like this solution, it's simple. When setting DessertIndex, add a call to NotifyOfPropertyChange("SelectedFood") so elements that are binded to SelectedFood can be updated
0

Just To add on the great answer by Colin Thomsen.

You could also use C# dynamic keyword to make this solution work with pretty much every container type. Or even bind to multidimensional containers "{Binding Food[{Binding DessertIndex1}][{Binding DessertIndex2}]}"

public class ContainerDoubleAccessConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            dynamic idx1 = values[0];
            dynamic idx2 = values[1];
            dynamic container = values[2];

            return container[idx1][idx2];
        }
        catch (System.Exception err)
        {
            DebugTrace.Trace("bad conversion " + err.Message);
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.